Variable Width Fonts

From Spheriki

Jump to: navigation, search

Welcome! In this tutorial we'll learn about variable-width fonts, or VWF for short. We will cover the definition of a VWF, how a VWF works, and how to implement one within Sphere using JavaScript. It is assumed you have some knowledge of JavaScript and object-oriented programming.

Contents

What is a VWF?

In the earlier days of computing and video gaming, applications typically used non-proportional, or monospaced fonts. These fonts are named for the fact that each letter is the same width, which was important because of the limited power of computers at the time. Below is an example of a monospaced font:

The quick brown fox jumps high over the lazy dog's kennel.

As time progressed and computers became more powerful, it eventually became feasible to design and use fonts with letters of varying widths. These proportional, or variable-width fonts can require more work to implement than monospaced ones, but are more compact and provide a cleaner interface for users. Most fonts, such as the one used for this text, are variable-width fonts.

How a VWF works

In general, when we want to print text to the screen, we need two things: a font and some text. If we are simply loading an image and processing it into letters, then every letter is treated as being the same width and height; height is not an issue since we can print to anywhere on the screen. If we are using a monospaced font, then the output would appear normal because every letter is as wide as the program thinks it is. If we are using a variable-width font however, the letters would be spaced apart from each other because they are not as wide as the program expects them to be. This is where a VWF routine comes in; we have to tell the computer how wide each letter is. So we add to our program a width table, an array which stores the widths of each letter. Then when we want to print text, instead of just printing everything as-is, we print a letter at x, find its width in the width table and increase x by that amount. This way when we print some text, each letter will be right next to each other, which is what we want. The following section is one example of how to implement this functionality.

Implementing a VWF in Sphere

Setting Up

We'll now look at using a VWF within Sphere. First, ensure that you have the latest version of Sphere installed on your computer. Now, open the Sphere Editor and create a new project called "VWF_Example". This will open the Project Explorer, which allows you to manage the files within your project. While Sphere allows you to use its own fonts, for the purpose of this tutorial we will use our own image, which contains a full ASCII font. Once you have downloaded it, select "File -> Import -> Image to Font..." in Sphere. Browse to where you downloaded the font and select it, then save the resulting font in your project's "fonts" folder as font.rfn. When the program asks if you are using a 1-pixel border, click "No", and the font will be added to your project. Now, right-click on the "scripts" folder and select "New...". This will open a new tab enabling you to write a game script. Copy and paste the following code, and save the script as main.js:

// Create a Font object to store our font in
var font = LoadFont("font.rfn");
 
// Entry point for our project
function game()
{
  // Render text to rear video buffer
  font.drawText(0, 0,"The quick brown fox jumps high over the lazy dog's kennel." );
 
  // Switch and clear buffers so that text is displayed
  FlipScreen();
 
  // Wait for user input
  GetKey();
};

This script loads our font into a Font object, which is then used to draw text onto the screen. However, if you run this script (by pressing CTRL+F5), you will notice that the letters are very far apart. This is because although we are using a variable-width font, Sphere still treats it as a monospaced font. Our next step then is to manually account for this spacing.

Writing the VWF routine

Create a second script for your project, then copy and paste this code and save it as VWF.js:

// VWF routine
function drawTextVWF(font, VWF_Table, x, y, text){
        // Render loop
	for (index = 0; index < text.length; index++){
                // Output current letter at x, y
		font.drawText(x, y, text.charAt(index));
 
                // Reposition according to the width of the current letter
		x = x + VWF_Table[text.charCodeAt(index)];
	};
};

The function in this script is essentially an extension of Font.drawText, but instead of drawing the text all at once, one letter is drawn at a time at x, and x is increased by the width of the letter drawn (which is fetched from the width table array). So if this function is used to draw text, it will do so according to each letter's specified width.

Using the VWF

The last major step in this tutorial is to implement the routine. Return to main.js and modify it so that it resembles the code below:

// Ensure that VWF code is included
RequireScript("VWF.js");
 
// Example width table
//                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
var widthTable = [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 0
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 1
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 2
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 3
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 4
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 5
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 6
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 7
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 8
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// 9
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// A
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// B
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// C
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// D
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,	// E
		  8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8];	// F
 
// Create a Font object to store our font in
var font = LoadFont("font.rfn");
 
// Entry point for our project
function game()
{
  // Render text to rear video buffer
  drawTextVWF(font, widthTable, 0, 0, "The quick brown fox jumps high over the lazy dog's kennel." );
 
  // Switch and clear buffers so that text is displayed
  FlipScreen();
 
  // Wait for user input
  GetKey();
};

Aside from replacing font.drawText with drawTextVWF, the script now includes an example array (written in table-like format) to store letter widths. Since no letter is wider than 8 pixels, we will assume for now that each letter is 8 pixels wide. The comments above and beside the array represent hexadecimal numbers, which are base 16 rather than base 10 (i.e. 10 in hexadecimal is equal to 16 in regular numbers, and 10 in regular numbers is equal to A in hexadecimal). So, the hexadecimal value of "d" would be 6F, for instance.

Now that we have implemented a working VWF routine, you may test it by running the project. You should see that the letters are much closer together than before, though some are still slightly apart. This can be fixed by finding out the width of each character (by viewing the font in Sphere) and adjusting the width table array accordingly.

Conclusion

In this tutorial you have learned how to implement a VWF. Though this tutorial demonstrates how to do so in Sphere, the same basic principles - create a width table, load a letter a at x, fetch the width of a from the width table and increase x by that amount - can be applied in any language, particularly in assembly language. With this knowledge, the font, language and platform you are using do not matter; the underlying concepts are what is important.

Personal tools