The Playground: AoW Title Screen Part 2
I, uh… kind of forgot to write part 2 of the series. So here it is.
Last time, I talked about the audio side of things. This time, we’re painting pictures. Writing the audio library myself was probably not the best choice if this was going to be a released project, but doing so ended up teaching me a number of key fundamentals for manipulating binary data in JavaScript, which would prove invaluable for the graphical side of things. I had actually come up with a couple of approaches to how I’d do this, with the first being to extract all the image data right from the game files and converting them to PNGs, then using those with HTML/CSS to build the page.
As I said in the beginning of the last article, I started off using the documentation on the Jongware website and the AoWRead documentation to figure out the Age of Wonders 1 version of the ILB file format. Sorting through these, as well as using a bit of intuition, I eventually managed to put together a basic C++ command line program that would take an ILB file and dump all the images, composited where applicable, into a folder for me. Here’s an example of one of the composited images:
The Triumph Studios logo from the title screen image library. The image is composed of a faded background glow and a solid logo (that isn’t actually solid!).
After building out a basic, static version of the title screen using HTML and CSS, I decided it was okay, but it wasn’t nearly as accurate as I wanted. One issue was simply that the ILB format allows for different effects to be applied to the image at render time, such as additive and multiplicative blending. My PNG exporter cheats when writing out the composited format, so it wasn’t ever going to be accurate simply because PNG doesn’t support the blending modes needed. I’m sure I could use CSS tricks and not pre-composite the images, but at that rate the converted images were going to end up a larger file size than the original ILB to begin with. Additionally, text was going to be a major pain because all the fonts were stored as bitmap graphics in ILB files as well.
This led me to the current solution: Instead of pre-converting and using HTML and CSS to render, I’d use what I learned about reading binary data from the IT player library, combined with what I learned about the file format from the C++ project, and dig in to learning HTML5’s Canvas system. One of the first things I did was look up if Canvas supported more interesting blend modes than bog standard alpha, just to be sure. It does, which greatly simplifies the rendering system.
So with the feasibility study done, it was time to get started. The ILBFile class I wrote started out as a barebones copy and paste of the ITSong class, since the majority of what it was doing was very similar: get the file from the server, and run through the individual pieces of it to pass them off to their class constructors that do all the heavy lifting. I decided to put the rendering code for the individual images into the ILBImage class since there’s a lot of metadata that rendering depends on, simplifying rendering the overall image down to “call draw with the position” instead of having to handle all the layers and their offsets and rendering modes every time. There was one special blending mode I had to handle at loading time, especially since one of the title screen logos actually uses it. The documentation I have calls it “intensity” and it basically just makes the whole image almost twice as bright before rendering it with additive blending. I had to modify the pixels before creating the javascript image object simply because there’s no blending mode that’s equivalent, and all the basic tricks I was trying weren’t ending up quite right. Oh well, it got the job done.
Finally, I had image rendering. It was time to start doing stuff with that. The first thing was getting the scrolling background working. This was mildly complicated since I wanted to be able to handle arbitrary window sizes. Eventually I settled on a for loop, drawing images until the next one would be completely off screen. Interestingly, this ended up being one of two ways my reproduction ended up handling things better than the real thing, since Age of Wonders’ program didn’t account for large resolutions when drawing the title screen. It was fixed at only drawing two copies of the backdrop, so once the second copy was far enough to the left that it was no longer overdrawing (it’s only 1514px wide) you ended up with a smear of the last column as it scrolled until it hit X=0 where it switched to being the “first” copy, and the game started that whole routine over.
Once I had that done, it was time to move to text. The basics of this was made really easy by Triumph’s great decision to have the image IDs for each character in the font match up to it’s ASCII code, making the initial string rendering code a basic for loop iterating over the string and drawing each character by it’s ID. But there was a snag: None of the fonts for the static version text in the bottom right corner were the right color. In the end I determined that they were simply taking advantaged of the fact that the font images for that particular font used the 8-bit indexed mode and choosing the pixel colors based off that. It was a nice idea, but would introduce a bit of extra overhead if I were to do that in JavaScript.
Instead, I cheated. Sort of. I wrote a function that would use the font’s image data to figure out the width of the string (which I’d use later anyway), then use that to build an image object to render the raw font to. From there, it was a basic matter of using blending modes to overwrite the non-transparent pixels, then drawing that on the final canvas. The width-finding function ended up being very useful for string positioning as well, making layout a breeze.
The fun came from drawing the credits. The fading text using a fancy font with a built in drop shadow, the logos, and the timing. All of it drove me nuts! The first thing I had to do was figure out where on the screen everything needed to be. I figured out the game was basing all of it’s key layout on a 640×480 box centered on the screen, which wasn’t an uncommon (although cramped) resolution at the time. I used CSS to set that as my minimum, then started figuring out offsets. A lot of this was simply using Visual Studio’s debugger to pause execution, using the mouse cursor to count pixels relative to some landmark, then putting that in my table of layout info. The various fades and whatnot actually made me add a render alpha parameter to the ILB drawing code. Amusingly enough, due to the way I draw the text, this ended up being the second way my reproduction handling things better. In the real Age of Wonders program, the blending code didn’t handle alpha AND additive/multiplicative blending (which was used by the main font for the text and it’s drop shadow, respectively) as well as it could have, resulting in some minor but obvious visual hiccoughs if you knew to look for them.
The orbs at the bottom were a walk in the park by comparison. Each has a slight glow behind it which is just one of the images from the ILB in additive blending mode. Then you have the orb image itself, where the only complicated thing was the mouse listening code to determine if the mouse was hovering and/or clicking in the orb’s bounding box to determine if it should draw the normal/hover/active image. In addition, it also draws the orb’s label if the mouse is within the orb’s bounding box. For kicks, I also added a way to have a callback fire when the orb has been “clicked” which I use for the exit orb to return you to the home page.
And there you have it. A reimplementation of the Age of Wonders title screen, with the added benefit of using the original game files. PlsNoSue, Triumph…
Comments