Going forward, I will be separating the more in-depth posts about specific subsystems, and the general update for each week. For example, I am working on a post all about the interesting and very confusing nature of sprites, their data, and their animations (with some neat graphics!). In a different post, I want to illustrate the interconnections of the engine and the overall shape, to really show the path through it that the game takes and the path of translation as well. However those will be coming whenever they are ready, where as the sunday/monday post will be a more straightforward update. So, for today, here’s an update about the last couple of weeks.
The last two weeks I mentioned that the primary goal was translating the structure of the engine, and a lot has been done in that regard. The files that will be relevant to this are:
– Kernal.GS, Driver.GS, Logic.GS, Sprite.GS, Sprite_list.GS, Misc, Compression.GS, and Cyc
As mentioned before, Kernal and Driver are sort of the backbone of the game engine. Driver acts as the interface with the Apple IIGS hardware (primarily), while Kernal is abstracted a little bit further, not dealing directly with the hardware, but containing the main game loop, and many basic functions. Together, they form the framework of the engine as a whole. You can think of the game as a stage play, where Kernal is the director, Driver is the tech crew, the assets are the set dressing, and all the other files and subsystems are the actors. Kernal might say ‘fade out’, but ultimately Driver will turn the lights down.
However, moving to ScummVM, much of that behind the scenes work can be done by the director without a tech crew. As such, I took a look at the functions in these files to find out what needed to stay and what could go. My real notes are pretty messy, but this illustrates the idea for Driver.GS:
So after doing that, it’s clear that what’s left of Driver is basically screen drawing, and input. The backend of which is handled by ScummVM already. What the immortal engine needs to do, is give ScummVM the finished, cleaned up data. What it does not need to do, is tell ScummVM how to draw that data on the screen. Getting input from different devices is handled by ScummVM, the engine just needs a way to know if the right input has been pressed. Both of those things are abstracted from the Driver level, so we can conclude that they can be part of Kernal.
What about Kernal then? I’ll spare everyone the much larger list of functions and just say that Kernal is being treated as part of the ScummVM engine object itself.
Okay, so what have I done with those Kernal/Driver files? Quite a lot actually. The big thing for me was getting the general structure down. By this I mean the pre-loop setup, and the main game loop. These are both found in immortal.cpp, but everything after that is found in the individual files. The game loop, and especially the initialization before it, primarily use functions from Kernal, and then the game loop calls the skeleton of each of the other subsystems when it needs to. To clarify, I’ll use sprites as an example. Sprite data needs to be loaded from the respective files before it can be used, and the act of loading from the file and making it useable for the sprite code itself, is really the job of Driver and Kernal. So although I’ve added Sprite.cpp, which will handle individual sprite functions (like super-sprites, or manipulating sprite properties, etc.), the loading of sprite data, is handled by a Kernal function. The result is that I’ve been filling out the game loop by implementing these Kernal/Driver functions, and then making my way from there into the individual pieces. So far, I’ve got the main through line of the engine, and because of that, I have a fairly clear idea of what each step in filling out the rest will be.
The structure of a game engine is sort of like a train. It has a start, where people get on board. And at the final stop, the image goes to the screen. There are many stops along the way, where some passengers get out, and different ones get on. Maybe some will get out, go to a shop, and come back wearing a new hat. Those stops are where the magic of the game happens, but the first step is to make the train able to get from the start to the end. The result is something like this:
Now of course all that can be shown right now is the frame around the game screen, because that is stored as a bitmap with no extra processing over it. But I will be adding in the other layers before it as I fill out more bits of the engine. So right now it starts with the window frame (that’s in loadWindow()) being added to the screen buffer, and it ends with the screen buffer being copied to the ScummVM surface. But for example as the sprites subsystem gets filled out, those Driver functions for ‘blit’ing will be implemented and start acting on the buffer before it gets copied to the surface.
At some point I will have a better explanation of the process. The path is sort of inside-out, starting where ever the game loop is and expanding out into those stops between the start and end, but each of those stops is then handled in a more outside-in way, creating the skeleton of the subsystem and filling it out.
Kernal and Driver were the big ones, but I did also get started with Sprite.GS, Sprite_list.GS (these are sort of mixed in with kernal, but they are how sprites are defined in the engine, which I’ve made quite a bit of progress on), as well as a little bit of Logic.GS (this is the next big one to get into, so I’ve started with some of the smaller functions that don’t depend on anything), as well as Compression.GS (which I talked about previously. It’s translated, although I will likely find errors or adjustments once the engine actually needs to uncompress data), and most recently Cyc. Cyc is the sprite animation system in the game, and although I know how it works, implementing it has been somewhat challenging. I’m sure I’ll have more to say on it in the next update post.
So next up, finishing the work with sprites, and then on to Logic, the subsystem that keeps the game ticking!