Jun 1, 2011

Bitmap Fonts

While I haven't written anything about Bulldog in the last 6 weeks. I definitely haven't been idle in the coding/design department.

Following on from my last post about the icon graphics, I've drawn about 15 additional icons for in-game objects. I've also started to put together the user interface, with displays for the player's Health, Energy, Water and Morale stats. I've written alot of additional behind the scenes systems that help hold everything together, but aren't really that interesting in terms of function, so haven't bothered to talk about them in the blog.

However, this past weekend I tackled a feature I've had on the TODO list for quite some time : creating a better font rendering engine. The standard font routines available in SlimDX (or DirectX for that matter) are terrible in both performance and functionality.

The usual way of overcoming this is to produce a bitmap representation of a font at a specific size and then create a system that generates quads for every letter in the text you want to render and apply the individual letter bitmaps to the quads for rendering. I've seen this approach go wrong in some commercial AAA games and produce horrible artifacts at the edge of letters where they've partially overlapped without proper blending, so I decided to try a slightly different approach.

Rather than have a quad for every letter, I create a single big quad for the entire text, and then generate a bitmap of the text to be displayed in memory by placing the letter bitmaps in the appropriate positions, then slap that bitmap onto the quad for rendering. There's some overhead to constructing the text bitmap, but it only needs to be generated once (unless the text changes), and from then on its a single large quad with a texture, which should be much faster than 100's of small quads.

To test the font engine, I created a bitmap font with a hand-drawn appearance, so that it has a comic-like quality to it, but still is quite readable and the letter forms are consistent. The font itself was drawn in Illustrator, then output as a high resolution bitmap, which I then downsampled in Photoshop.

A screenshot from Adobe Illustrator showing the curves used to create the letter shapes.

Creating my own font means it should match in better with the overall graphic style of the game, than if I used a very clean font like Arial. The image below shows the completed font at 22 pixel resolution, which I've called "Olivia22".

The finished "Olivia22" font.

Throwing together the bitmap font engine and drawing the font didn't actually take as long as I thought. The font took about 8 hours to do all 95 glyphs, and the font engine was about the same. The part I was surprised about was how long it took to setup the kerning information for the font.


Kerning

Kerning is the process of adjusting the space between letters in a word to make the characters sit together in an aesthetically pleasing manner. Unless you're involved in graphic design it may not be apparent that a process like kerning is even required. Kerning is typically done with pairs of letters. A "kerning pair" defines the gap between two particular letters, and at render time each letter pair is checked against the list of kerning pairs and the second letter is offset left or right by the appropriate amount.

For overhanging letters such as "W" or "V", kerning is particularly important, especially when paired with letters like "A", or any of the curvy lower case letters, such as "o", "c" or "a". So for my font to "read well" I had to create kerning pairs for problem combinations of letters. The process took many hours of adjusting values, running the program against a reference text and inspecting each word individually. Over the course of 6 hours I put together close to 500 kerning pairs and just about had my eyeballs fall out of their sockets.

The image below is part of the rendered reference text, showing the kerned version of the font. (This is actually from a work in progress, so I've since tweaked some of the pairs to be better).

A crop of part of the rendered reference text


Even after so much work the result is far from perfect. The biggest limitation with the way I've implemented the font renderer is that the smallest distance a letter can be moved left or right is an entire pixel. In many situations, the "correct kerning" is a movement of less than a pixel, so the space can never be correct for that particularly instance. This is less of a problem with larger font sizes, but with the 22 pixel high font I've created, the kerning values are within the range of +3 to -3, which is pretty small, and leads to some compromise.

In an ideal world the font renderer would use the original vector graphics as the source for the letters, and create its own anti-aliased versions at whatever size is required, however I can't be bothered creating such a thing at this stage, especially when I'm trying to hit an end of year deadline. Perhaps in the future?

Another thing which has become apparent is that my process of kerning is time consuming and fiddly. My plan is to create another 3 or so variations on the current font, (ie different sizes and normal/bold versions). If its going to be 6 hours of kerning for every one of those I'll go insane. So I've come up with an improved workflow for kerning that should shave hours off the time.

The current workflow involves setting the kerning values in the font's data file, running the test code that takes the reference text and produces an output png of the rendered text, loading the png in photoshop and looking over the entire text to spot problems and then repeating the entire process.

The improved workflow relies on me getting the TextBox control working, and adding the ability to tweak the kerning per character pair directly in the text using the cursor keys. This should greatly speed up the process, as the kerning changes will be visible immediately, and without having to load the output in an external application.

Apr 14, 2011

Progress Report - Some graphics!

I've been doing a lot of behind the scenes work in the last few weeks, but progress has been a bit slow due to my time being taken up by other factors. The windowing system is good enough now that I shouldn't need to mess with it for quite some time, which is good as I need to concentrate on gameplay related features.

Recently I've been looking at the inventory screen and how the player interacts with items and objects in the world. To this end, I spent some time putting together some better graphics for the inventory screen, (previously I had dodgy placeholders). The visual style of Bulldog is something I've been thinking about for quite some time, and I think I've settled on a look that I'm happy with:


The 2D images above are intended for use in the inventory screen. In the game world itself the plan is to use 3d models shaded in such a way that they take on a similar appearance.

The visual look is heavily based on the style I developed for my web comic, Asleep at the wheel. I haven't posted a new comic in almost two years due to becoming a first-time father. Before the baby came along it was taking me several days to put together a weekly comic and pretty much any random event would disrupt the process enough that the comic would be late, so it simply wasn't going to happen with a newborn added to the mix.

I'm keen to get Bulldog to a good enough state to be able to show off some screenshots some time soon, but there's still a lot that needs to be done before I can do anything like that. These simple in-game icons are a step in the right direction though.

Mar 28, 2011

Bugs

As part of this blog I wanted to talk about my failures as well as my successes, so in the spirit of that I'll talk about things which have tripped me up recently and what the solution was, in the hope that someone else with the same problem might be able to learn something.

Full Screen Mode
One of the early things I implemented in the main engine was the ability to go to full screen mode. It's not a big thing, its pretty much in every game. Though you need to properly reset the Direct3D device and free up all your resources and load them in again in order for it to work. Which can be tricky for those unfamiliar with Direct3D to get their head around. I consulted many tutorials and got it working and then ignored it for several months.

I switched the game to full screen mode on the weekend and the screen resized to fit the entire screen but the rendering stopped, and the entire app hung. Obviously I'd broken something in the last few months. To cut a long story short, I'd implemented a new way of handling the Resize events and that was firing when it shouldn't and was stopping the rendering. After I fixed that, it worked again... mostly.

My UI elements, (which admittedly didn't exist when I coded the full screen mode) were not receiving mouse clicks correctly, as though the coordinate systems were offset somehow. I discovered that the actual dimensions of the full screen window weren't correct. Though I was setting it to be 1680x1050 (the max resolution of the laptop I do development on), the window was coming out as 1664x1015 or something. Stretched across the entire screen this would cause misalignment of the mouse cursor vs the controls and exhibit the behaviour I noted.

After much googling, I finally discovered that you need to set the borderstyle of the form to none when going to fullscreen and then restore it when switching back. When I originally implemented full screen mode that little quirk wasn't mentioned in the tutorials I looked at, and because it looked correct, I assumed it was correct, due to the perception that full screen mode should have been a cinch.

I guess the lesson here is never assume that you're done correctly just because it's a simple task, and the output seems correct.

Mar 14, 2011

The Bigger Picture

It's overdue for me to talk about the "bigger picture" of what Bulldog is supposed to be, so in this post I'll hopefully begin to shed light on what I have in store.

Ambition
Bulldog is a very ambitious project. It may not seem that way based on what I've discussed so far in the blog, but my long term plan for Bulldog is grand in scope. It may take 5 years for me to fully realise what I have in mind, but the project is somewhat modular, and can be broken down into more manageable milestones.

As mentioned in previous posts I plan to have a release out by the end of the year. Beyond that I plan to release new content and upgrade the game at regular intervals, slowly building Bulldog to where I want it to be. This strategy is pretty much essential to have any chance of success, as I am doing this project in my spare time and if I decided to not release anything until its "perfect", there would never be a release. Something (albeit flawed) is better than nothing.

In terms of what genre Bulldog falls into, the best I can come up with is open world survival RPG. Open world is perhaps not the exactly right definition, it's more akin to how Minecraft or Dwarf Fortress generate new worlds and don't force a specific storyline on the player. Perhaps "open-ended" is more accurate, but I haven't really heard that term used when describing this sort of game. The key thing here is that the player drives the story through their actions (or inactions) rather than by completing a series of quests or puzzles in sequence and then getting a nice ending cut-scene.

Survival is the ultimate goal. There will be many variations to achieving this goal. To some players survival will mean exploring the gameworld, scavenging supplies, fighting off threats, amassing wealth and levelling up.

To others it will mean building up a thriving community, rebuilding civilisation and having to content with "the greater good", rather than just yourself.

Origin Scenarios
A key feature I'm planning for Bulldog is the ability to select a specific survival scenario when you start a new game which will define and shape the generated game world. This will hopefully allow more re-playability, as well as allow more options for the player to customise their survival experience.

The different origin scenarios will have a impact the game quite differently. For example, in a zombie outbreak scenario, you'll be fighting off hordes of the undead in a messed up but relatively intact world. There will be plenty of stuff to scavenge, but there will also be danger lurking around every corner, and you don't even want to contemplate what will happen if you don't get back to camp before dark.

In contrast, consider a post nuclear war scenario where most major cities will have been completely obliterated and entire areas will be uninhabitable due to radiation. Nuclear winter may have set in and food and drinkable water will be scarce, weather effects such as dust storms and intense thunderstorms will batter your settlements and destroy anything the nukes left standing.

The origin scenario I'm planning to include in the end of year release is a Desert Island, similar to the situation in the movie "Castaway", starring Tom Hanks. You've washed up on a desert island with a bunch of random stuff and have to survive. I chose that scenario for the simple reason that the player can be contained within a finite space as opposed to the practically infinite dynamic world generation I have planned for the final version. Getting that sort of terrain generation working correctly is going to be a major challenge, and I'd rather start with something simpler, such as a desert island.

An interesting point that people may not realise is that "desert island" doesn't actually imply the archetypal small  pile of sand with a single palm tree. The "desert" part of the phrase doesn't even imply an arid, desert-like climate. It actually comes from the word "deserted", literally meaning there isn't anyone else around.