2009-12-13

Font Dilemma

Jeff’s PackedFont classes can do everything that my Font and MonoFont classes can do. They store their data more efficiently and require far less processing time to render their glyphs than my fonts. Why not just remove my fonts and simplify things?

I think I’ll do just that unless I can think of a good reason not to.

2009-12-13

Creating Fonts and Bitmaps

More work on fonts. Jeff’s solution for creating PackedFont fonts is fantastic - instead of mucking around with u16 arrays, he subclasses the fonts and does all of the work for you. Instead of this:


PackedFont1* myFont = new PackedFont(somearray, somewidth, someheight, blah, blah);

…you have this:


NewTopaz* myFont = new NewTopaz();

So much easier.

I’ve shamelessly stolen this idea and reworked the existing “FontBitPacker” application so that it follows this pattern. I’ve heavily modified it so that the app will convert BMP files to either MonoFont, Font, PackedFont1 or PackedFont16 font classes. As long as they have version 3.5 of the .NET framework, Windows users no longer need to faff about with PAGfx or the bmp2font Python script. The new “bmp2font” .NET console application (which the FontBitPacker has become) will do all of the font conversion work needed for Woopsi.

This pattern seemed like such a good idea I’ve used it for bitmaps, too. Instead of converting BMP files with PAGfx, then using the “all_gfx” files to include the bitmap data before wrapping them up in a BitmapWrapper class, it is now possible to use a new “bmp2bitmap” .NET app to convert straight from a BMP file to a BitmapWrapper subclass.

These new programs have enabled me to delete the PAGfx binary and the files it converted from the Woopsi demo folder. I’ve replaced the converted files with classes converted with bmp2bitmap.

2009-12-09

Fonts, Styles and Bugfixes

Thanks to Jeff, Woopsi now has a smorgasbord of new fonts. They are all included in the main libwoopsi folder, so I’ve had to tweak the makefiles in all projects to accommodate the change.

The fonts include standards such as MS Sans, Garamond, Times New Roman and Courier. Some of them are available in more than one size.

Not all of the fonts Jeff supplied were usable, due to being too large, too small or having other problems. The PackedFonts system has size limits due to using u16s instead of u32s in a variety of places; the limits should be trivial to remove (or at least extend) but it’s probably a good thing that absurdly-sized fonts aren’t allowed. At least one of the fonts was too small to be legible. Others had strange vertical alignment problems. I still need to remove some of the troublesome fonts.

Including all of the fonts in the library has no impact on projects built with standard makefiles, but it vastly bloats the size of the demo project that’s built with VC++. I suppose the makefile must include all .cpp files regardless of whether or not they’re used. Not a problem for end-users, though.

Having some example fonts allowed me to change the way Woopsi was working with its original two fonts - the system font and tiny font. Instead of needing to manually instantiate a Font object and pass in the data comprising the fonts, they’re now implemented as classes. To create an instance of the tiny font, include “fonts/tinyfont.h” and call “new TinyFont()”. To create an instance of the system font, include “fonts/topaz.h” and call “new Topaz()”.

The new name for the system font hints at another change - I’ve replaced the default font. Topaz, apart from being ugly, is a fixed-width font. A considerable amount of screen real estate is taken up with the blank space between letters. Using Jeff’s PackedFont classes I’ve replaced Topaz with NewTopaz. More text can now fit on the DS’ screens, the UI looks more attractive, and as an added bonus, Woopsi looks more like my WinUAE setup.

Along with these changes, I’ve ripped out the global “systemFont” and “tinyFont” objects. These were created in the woopsifuncs.h file. However, tinyFont was only used by the Debug class (which now creates the font itself), whilst systemFont has been absorbed into a new “defaultGadgetStyle” object.

Previously, most of the gadgets in Woopsi could receive a pointer to a font as their final constructor argument. If no font was supplied they used the systemFont instead. They pulled all of their default colours from static members of the “DefaultStyle” class. This worked well enough, but it was an ugly solution.

I’ve re-worked this so that instead of receiving a pointer to a font in their constructors, gadgets can be passed a pointer to a GadgetStyle object instead. GadgetStyle objects contain definitions for all colours a gadget uses and the font. The gadget copies the properties of the object into its own internal GadgetStyle instance. If no object is supplied, they copy the information from the global defaultGadgetStyle object instead. This means that:

  • It is much easier to change the font and colours for all gadgets that need to be created;
  • It is much easier to change the font and colours for a subset of gadgets that need to be created;
  • Colour and font information is stored together.

All of this represents breaking changes.

In other font/style news, the PackedFontBase::isCharBlank() method returns the correct value. I’ve added a packedfonts example program which demonstrates all of the fonts in Woopsi. I’ve also added a defaultstyle example which illustrates how to change the properties of the defaultGadgetStyle and alter the appearance of Woopsi.

I’ve made many other fixes. The ListBox draws correctly when it is dragged; previously, dragging upwards caused graphical artifacts to appear. It does not attempt to redraw the item at index -1 in its list. The CycleButton redraws itself correctly if it is clicked but it contains no options. The Label and its subclasses recalculate their text positions and redraw when their fonts are changed, a does the MultiLineTextBox.

There are a few fixes to the TextBox. It does not attempt to reposition its cursor if it contains no text. Its cursor jumps to the right location if its font is a PackedFont.

I’ve stopped the Graphics::floodFill() method from getting stuck in an infinite loop (not sure when I introduced that bug), and removed some unused bitmaps from the demo.

Finally, I’ve added the FileListBox classes to SVN. These were supposed to have been released in version 0.42, but I apparently forgot to check them into SVN and so they were omitted. This means that the FileRequester is broken in version 0.42. I’m just glad I still had copies of the files.

2009-12-06

Fixing the Fonts

The packed font system written by Jeff Laing has been broken since I refactored the bitmap system in Woopsi 0.40. I put together a new PackedFonts example project in order to identify and fix the problems, and the classes now work again. In addition, Woopsi now includes a “fonts” folder in its bonus directory, that includes 3 new fonts: Courier, CourierMono and Latha. Jeff wrote a demo with loads of fonts but I can’t seem to find the code, unfortunately, so I can’t add them to Woopsi.

I’ve also been hacking away at his bmp2font Python script. This is a Python 2 script that uses the devKitARM “grit” program to convert a BMP into a packed font class. It had a number of problems. Under Windows, it couldn’t find the grit program (the DEVKITARM environment variables use Linux-style paths, which don’t resolve properly). It didn’t put the resultant font classes into the WoopsiUI namespace (I must have introduced this after Jeff wrote the script), and it didn’t follow Woopsi naming conventions. All of these problems are now fixed.

In addition, there was still a minor clipping problem in the ListBox. This is fixed too.

2009-11-10

Bitmaps, Framebuffers, Drawing, and Fonts

The latest set of updates encompasses a substantial amount of fundamental changes within Woopsi. It now includes the following types of bitmap class:

BitmapBase

The most basic bitmap abstract class from which all others inherit. It defines the most fundamental properties of an immutable bitmap.

BitmapWrapper

Extends the BitmapBase with the ability to wrap around a raw u16 array and permits it to be used as a standard bitmap object.

MutableBitmapBase

Extends the BitmapBase with the ability to set the colour of a pixel at a given set of co-ordinates. Can also provide a non-const pointer to the raw u16 array. This is an abstract class from which all mutable bitmaps should inherit.

Bitmap

The standard bitmap object. Can produce a new Graphics object that has the capability of drawing to the Bitmap in the same way that the GraphicsPort draws to a gadget.

FrameBuffer

Almost identical to the Bitmap class, except it accepts a pointer to a pre-existing non-const u16 array in its constructor instead of creating the array internally. Intended as a wrapper for the framebuffer to allow it to be used as a bitmap object.

These changes supercede the changes discussed in the last post.

The drawing functions have been removed from the Bitmap class and split up into a class hierarchy:

GraphicsUnclipped

Contains all of the drawing functions previously stored in the GraphicsPort and Bitmap classes, minus any clipping code. Will draw to any instance of a class that inherits from the mutable bitmap class.

Graphics

Inherits from the GraphicsUnclipped class and adds simple clipping functions that ensure the drawing methods do not exceed the width of the bitmap being drawn to. Typically used when drawing to standard bitmap objects.

GraphicsPort

Inherits from the GraphicsUnclipped class and adds complex clipping functions that ensure the drawing methods do not attempt to draw outside the boundaries of a clipping rect, or array of clipping rects.

These changes mean that the basic drawing functions now only exist in one class, instead of being duplicated (with minor changes) in two places. The rationalisation also means that functions such as dim(), copy() and the XOR drawing methods are now available for use on bitmap objects as well as within gadgets.

In order to achieve this, the DrawBg array that previously allowed access to the framebuffer has been replaced with an array of FrameBuffer objects.

Changing these classes necessitated changes to the font system. All fonts that use unpacked bitmap data now expect to be supplied with a pointer to a bitmap object instead of a raw u16 array. Changing this required a rewrite of the rendering and clipping code in the Font and MonoFont classes.

The two standard fonts, “systemFont” and “tinyFont”, are now available as font global font objects. They are instantiated in the initWoopsiGfxMode() function in woopsifuncs.cpp.

These changes should bring a variety of benefits:

  • Fewer magic numbers flying around as bitmap width/height values are stored within bitmap objects instead of specified as parameters for every method;
  • Font bitmaps can be loaded dynamically from BMP files using BitmapIO;
  • It should be easier to add conditional compilation to the drawing methods in order to optimise SDL screen updates;
  • The drawing functions are no longer duplicated in several classes;
  • Bitmaps and the GraphicsPort have access to the same set of drawing functions.

There are a couple of new issues:

  • Blitting a bitmap to another bitmap seems to result in the occasional set of missing pixels at the start or end of the bitmap, probably resulting from the DMA hardware seeing old data (need to flush);
  • I need to check that the new structure is tidy.

2008-05-01

ListBox Finished!

The ListBox and ScrollingListBox (a ListBox with a scrollbar) are finished. I’ve added some more functions for working with the options within a ListBox and an alphabetical sort routine (I was looking into sorts for something else today, so decided to add one in). The ScrollingListBox features both smooth scrolling (when the list is dragged) and jump scrolling (when the scrollbar is dragged). The previously untested theories about how the scrollbars would work in this situation have all turned out to accurate. Hurrah!

As I haven’t put one up in ages, here’s a screenshot:

Woopsi ListBox

Another quick change - John requested a way to change the default colours for the gadgets. There’s now a static “DefaultStyle” class that contains all of the default colour data. Altering the variables in this class will cause any gadgets constructed afterwards to use the changed values as their colour settings. There’s also a font pointer that, if set to anything other than NULL, Woopsi will use as the system font. Again, that should be set before you any construct any gadgets that should use the alternative font, as the gadgets make copies of all variables. The developer is responsible for deleting that font when it is no longer needed.

Here’s a screenshot of a nasty salmon version of Woopsi made by mucking about with the new DefaultStyle class:

Woopsi Alt Colours

2008-04-14

Proportional Fonts

Thanks to Jeff’s hard work, Woopsi now has two proportional font classes. One works with 1-bit fonts, whilst the other works with 16-bit fonts. I’ve tidied up the existing font classes a little to support this, moving things out of the base classes into the subclasses.

Jeff also supplied a new version of his “bmp2font” Python script, which will generate the sourcecode needed to describe one of the new fonts. This is included in a new “pythonscripts” folder.

Lastly, I’ve fixed a couple of bugs introduced when I refactored the click/focus system. Screens now receive focus correctly when clicked (and get raised up the gadget stack). They also get dragged properly - they were being dragged when clicked anywhere instead of just the title bar.

2008-04-09

Bitmap Blitting with Transparency and Proportional Fonts

Another hefty set of updates today.

Following on from the requests made in the forum, I’ve added a new “drawBitmap()” method to the GraphicsPort class that will treat a specified colour as transparent. Any pixels of that colour won’t get drawn. This is a lot slower than the usual method, as it involves drawing the bitmap pixel-by-pixel instead of using the DMA hardware, so it should only be used when necessary.

In the same thread, Jeff asked for some improvements to the font system. I have moved the “drawChar()” function out of the TextWriter class and into the font classes, which means each font is now responsible for blitting itself. It offers a much more flexible system. In addition to this, I’ve split the FontBase class in two and added a new “FixedWidthFontBase”. Woopsi is now set up to handle proportional fonts. I just need someone to write a proportional font class (hint hint).

As part of the proportional font changes I re-wrote the “Text::wrap()” function. It’s a lot neater, faster and more efficient now. However, the change seems to have broken the scrollbars again (gnnk) so I’ll need to spend some time debugging it.

EDIT: Scrollbars fixed (or as fixed as they ever have been), plus I’ve fixed some other scrollbar problems I found.

2007-10-15

Woopsi Version 2 Ideas #2

Making font bitmaps is tedious. So tedious that I really don’t want to bother doing it, but there aren’t a lot of fonts in the right format around.

My solution to this is to draw on a huge existing pool of fonts, and write an Amiga font loader. Shouldn’t be too difficult, especially as the file format for the fonts is described in the Amiga developer documentation and header files.