MiGS Overview
A Minimalist Graphics Subsystem


Introduction

This document details the design and implementation of MiGS, the minimalist graphics subsystem used by the FreeType 2 demonstration programs. Its purpose is mainly to help writers of new demo programs, as well as developers who would like port the subsystem to other platforms.

I - Design goals

MiGS is a tiny graphics subsystem used to demo text rendering through the FreeType library. It was mainly written to provide the abilities to :


II - Surfaces, bitmaps and windows

A surface in MiGS models a drawable region where glyph images can be rendered, a surface always contains a bitmap descriptor as well as a few other things that will be described later in this section.

Some surfaces can be displayed, they are then either called windowed surfaces or screen surfaces depending on the nature of the device used to display them. Each device is implemented by a very simple driver in the MiGS code. Here are a few example devices that are or could be written to display surfaces :

- an X11 device
- a Win 32 GDI device
- an OS/2 Presentation Manager device
- a fullscreen SVGALib device on Linux
- a GGI visual device
- an OS/2 "Dive" device, or the equivalent Win32 "DirectX" device

etc..

NOTE: For now, only the X11 device was written and tested.. More devices should come later

Before explaining how to create a surface, we need to explain how MiGS manages bitmaps and renders glyph images to them.

1. Bitmaps :

A bitmap in MiGS features the following things :


MiGS uses the "Y downwards" convention, which means that increasing Y coordinates correspond to lower rows of the bitmap. Hence, the coordinate (0,0) always corresponds to the bitmap's top-left pixel.

The bitmap's rows can be stored either "downwards" or "upwards" in the pixel buffer.

In the first case (downwards), increasing memory addresses in the pixel buffer correspond to lower rows of the bitmap(e.g. PC video modes), and the pitch should be equal to the number of bytes taken by each row. The first pixel buffer byte corresponds to the upper row.

In the second case (upwards), increasing memory addresses in the pixel buffer correspond to upper rows of the bitmap and the pitch should be equal to the opposite of the number of bytes taken by each row. The first pixel buffer byte corresponds to the lower row.

In all cases, the pitch is the increment to be used to go from one bitmap row to the one below it.

The supported pixel modes are :

The bitmap's number of gray levels is only relevant for 8-bit gray bitmaps, and indicates the range of gray levels that can be found in the bitmap. If a bitmap as N gray levels, it is said to be N-grayscales, and the pixels within it must all have values between 0, considered as the background color, and N-1, considered as the foreground color.

N-grayscale bitmaps are crucial for the rendering of anti-aliased text.
 

2. Glyph images :

The glyph images that can be drawn on bitmaps through MiGS are bitmaps themselves, though limited to the following pixel modes :

1-bit monochrome glyph bitmaps

These can be drawn on any kind of bitmap. Note that only the "lit" pixels (i.e. the bits set to 1) are effectively drawn to the target, as opaque blitting isn't supported (remember, it's a minimalist library !)


N-grayscales glyph images (with any value of N >= 2)

These can be drawn to all RGB bitmaps (15, 16, 24 & 32 bits/pixel), as well as any other M-grayscales bitmaps. In the latter case, the values of N and M need not be equal, as the library is able to perform automatic conversions on the fly.

For example, it is possible to render a 5-grayscales glyph image into a 128-grayscales bitmap. Moreover, it is also possible to render a 17-grayscales glyph image into a 5-grayscales bitmap, even if this will result in a loss of quality. This feature is crucial in order to experiment easily with other anti-aliasing algorithms for FreeType
 

Note that you can only draw monochrome bitmaps to the following pixel modes : monochrome, 4-bit color and 8-bit color.

3. Windows and Screens:

In order to debug FreeType, displaying a surface in a window or in full-screen mode, is required. MiGS thus makes a difference between simple surfaces, which only contain a bitmap, windowed surfaces, which are used to display their content in a window, and screen surfaces, which are used to display their content in a full-screen mode (SVGAlib, DirectX, GGI or wathever).

A few important things must be said about non-simple surfaces.
 

Surfaces have also a few fields that are only used when displaying them in Windows :

a title string

This is simply a text string that is displayed on the title bar of the surface's window. It can also appear at the top or bottom of full-screen surfaces if the MiGS driver supports it. The title string can be changed with a call to grSetTitle, and is ignored for simple surfaces.


a refresh flag

This boolean flag is only used for window surfaces, and some fullscreen ones (depending on the driver implementation). When set, it indicates that each glyph image blit must be displayed immediately. By default, this flag is set to False, which means that demo programs must call the grRefreshSurface(surface) function to display the whole contents of a surface one it has been updated.

The refresh flag can be set with grSetSurfaceRefresh(surface,flag). Note that a single surface rectangle can be forced to be displayed with a call to grRefreshRectangle(surface,x,y,w,h) at any time.

4. Devices :

As said before, each device is in charge of displaying a surface in a given window or screen. Each device is managed through a very simple driver, described to MiGS through a very simple "grDevice" structure.

A grDevice contains, among other things, pointers to the functions used to:

- refresh/display a given rectangle of the surface to the window/screen
- listen events (key presses and mouse) and send them back to client apps.
- for windowed devices, update the title bar.

As said before, this is a highly minimalist system..
 


III - Important implementation issues :

1. Display surface negociation :

A display surface is created with the function grNewScreenSurface which takes parameters indicating which device should be used, the pixel dimensions of the requested surface, as well as its pixel mode.

Because of some device-specific limitations, the resulting surface's properties might not match exactly those requested for the call. Hence, a developper should always take care of reading a new display surface's bitmap descriptor in order to get its real dimensions, pixel mode and eventually number of grays.

The function grNewSurface will create a memory surface with the corresponding bitmap.
The function grNewBitmapSurface will create a surface from a pre-existing bitmap. This is useful to draw text on loaded images, for example.

Any surface (display or not) is destroyed with grDoneSurface.

2. Supporting 8-bit grayscale mode :

It is important, for the debugging of FreeType anti-aliased renderer(s), that _all_ devices should support the 8-bit gray mode. The number of gray levels can be fixed or negociated as required by implementation-specific issues.

As most existing devices do not provide direct support for such a mode, each 8-bit surface must thus contain :

- an internal N-grayscale bitmap, used as the target of all glyph drawings
- its own device-specific "image", which matches the display depth.

Each time the device's "refresh_rect" function is called, it should then :
- convert the grayscales within the bitmap's rectangle into the image's buffer and format.
- display the corresponding image rectangle.

This scheme is used, for example, by the X11 device.