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.
MiGS is a tiny graphics subsystem used to demo text rendering through the FreeType library. It was mainly written to provide the abilities to :
MiGS uses system-specific "drivers" in order to perform display
and event handling. The blitting functions are not device-specific. MiGS
can be built and/or used with no system-specific features, like for example,
to generate simple GIF, PNG, TIFF, etc.. images without ever needing to
display them.
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" deviceetc..
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 :
- a width in pixels
- a height in pixels
- a pixel mode, which indicates how the pixels are stored in the surface's buffer
- a pitch, whose absolute values is the number of bytes taken by each surface row
- a number of valid gray levels (see below)
- a buffer, holding the surface's pixels
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.
- 1-bit monochrome bitmaps. With "0" as the background, and "1" as the foreground.
- 4-bit color bitmaps, using an arbitrary palette.
- 8-bit color bitmaps, using an arbitrary palette.
- 8-bit gray bitmaps, using a given N number of gray levels in the range 0..N-1.
- 15-bit color bitmaps, also known as RGB555
- 16-bit color bitmaps, also known as RGB565
- 24-bit color bitmaps, also known as RGB
- 32-bit color bitmaps, also known as RGBA (though the A is ignored by MiGS)
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.Note that you can only draw monochrome bitmaps to the following pixel modes : monochrome, 4-bit color and 8-bit color.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
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.
- First, they might contain some system-specific data which is used to manage the display in a window or on the screen. This must be completely hidden to MiGS clients. Indeed, rendering to any kind of surface is achieved through exactly the same function calls.
Surfaces have also a few fields that are only used when displaying them in Windows :
- Second, they may contain a bitmap whose pixel mode doesn't correspond to the screen's depth used to display it. For example, the surface might contain an 128-grayscale bitmap, while the screen is in RGB24 mode. Some conversion must be performed to display the surface. This can either happen in the system-specific graphics library (e.g. on OS/2, a single Presentation Manager call is used to blit a N-grayscale image to any kind of window) or in the system-specific part of MiGS (e.g. the X11 MiGS driver must convert the surface's bitmap into the appropriate X11 image each time a repaint is requested). Again this must be completely hidden to MiGS clients
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 flagThis 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..
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.