The basics of Guichan

From Guichan

Jump to: navigation, search

Contents

The core library and back end libraries

Guichan is divided into two parts, the core library and back end libraries. The core library knows only of C++ and is unable to do any platform specific tasks such as perform drawing, check for user input or load images. To be able to do platform specific tasks the core library uses a back end library that provides the ability to do platform specific tasks. The back end libraries implements a couple of interfaces from the core library. At the moment there are five different implementations of back end libraries in Guichan, an Allegro implementation, a HGE implementation, an OpenGL implementation, an OpenLayer implementation and an SDL implementation.

Gui

Gui is the main object in Guichan. It contains the widgets of the GUI, it makes sure all widgets in the GUI perform logic, it makes sure all widgets in the GUI are being drawn and it takes care of distribution of user input to the widgets. At least one Gui object is needed in order to be able to use Guichan.

As the Gui object is a part of the core library it cannot perform platform specific tasks unless the Gui object is provided with that ability. The Gui object needs the ability to draw widgets, the ability to check for user input and the ability to load images. This is provided by giving the Gui an implementation of the Graphics object and an implementation of the Input object.

gcn::Gui* gui = new Gui();
gui->setGraphics(graphics);
gui->setInput(input);

To be able to create a GUI with widgets, widgets must be added to the Gui object. However, the Gui object can only contain one widget, called the top widget. As there are widgets in Guichan implemented using the composite design pattern - such as the Container widget - widgets can be added to widgets meaning there is no end to how many widgets a Gui can contain. The most common widget to use as the top widget is a Container widget.

gui->setTop(topWidget);

Here is an example of a hierarchy in Guichan when the top widget is a Container widget:

Gui +-> Container (Top) +-> Button
                        |
                        +-> Container +-> CheckBox
                        |             |
                        |             +-> Label
                        |
                        +-> Container +-> Slider
                                      |
                                      +-> Label
                       

As Guichan is a non intrusive library it's up to the user to tell when the Gui object can perform logic and when can it can perform drawing. As this is done by calling two different functions a game can have different frame rates and logic rates.

if (callDraw)
{
    gui->draw();
}

if (callLogic)
{
    gui->logic();
}

When draw is called are all widgets in the GUI hierarchy are traversed and told to draw themselves using the Graphics object provided to Gui. When logic is called is user input checked and distributed to all widgets using the Input object provided to Gui and all widgets in the GUI hierarchy are traversed and told to perform logic.

Graphics

Graphics is an interface in Guichan used to perform platform independent graphic tasks. Graphics contains functions for drawing lines, rectangles, images, text and pixels and functions for setting clip areas. Graphics also contains states, such as the colour to use when drawing.

graphics->setColor(gcn::Color(0xffffff)); // The colour to be used when drawing. From here on, white will be used.
graphics->drawLine(10, 10, 100, 100);
graphics->drawRectangle(gcn::Rectangle(0, 0, 250, 250));
graphics->setColor(gcn::Color(0xff00ff)); // The colour is changed. From here on, pink will be used.
graphics->fillRectangle(gcn::Rectangle(400, 400, 10, 10));
graphics->setFont(font); // The font to be used when drawing text.
graphics->drawString("Hello world!", 23, 57);

To restrict drawing of certain areas Graphics contains a stack of clip rectangles. End users normally don't need to bother with the clip area stack as it is automatically taken care of by Guichan. The top of the stack is the current clip area used when using the Graphics object.

graphics->pushClipArea(gcn::Rectangle(100, 100, 100, 100)); // Drawing outside the rectangle is discarded.
graphics->drawLine(0, 150, 600, 150); // As the line is broader then the clip area not all of the line will be drawn.
graphics->popClipArea(); // The clip area is restored to the last pushed area.

The Gui object needs a Graphics object in order to be able to perform drawing of the GUI. In Guichan there are a number of implementations of the Graphics interface found in back end libraries. There is an Allegro implementation, a HGE implementation, an OpenGL implementation, an OpenLayer implementation and a SDL implementation. The behaviour of the implementations may vary, for instance the colour state of the Graphics object does not effect drawing of images and text in the Allegro and SDL implementation but do effect drawing of images in the OpenGL implementation.

Each implementation needs to be initialised in some way. The Allegro implementation performs all drawing on a user provided bitmap.

graphics = new gcn::AllegroGraphics();
graphics->setTarget(bitmap); 

The OpenGL implementation uses raw OpenGL commands to perform drawing and sets up a 2D orthogonal projection before any drawing is started. All matrices are restored automatically when drawing is done (The automatic set up of 2D orthogonal projection matrices and restoring of any previous matrices only applies when OpenGLGraphics is used with a Gui object as the Gui object calls the functions Graphics::_beginDraw and Graphics::_endDraw() prior and after drawing of the GUI).

graphics = new gcn::OpenGLGraphics();
graphics->setTargetPlane(640, 480);

The OpenLayer implementation works like the OpenGL implementation.

graphics = new gcn::OpenLayerGraphics();
graphics->setTargetPlane(640, 480);

The HGE implementation uses HGE to perform drawing and doesn't need any initialisation.

graphics = new gcn::HGEGraphics();

The SDL implementation performs all drawing on a user provided surface.

graphics = new gcn::SDLGraphics();
graphics->setTarget(bitmap);

Input

Input is an interface in Guichan used to perform platform independent input grabbing. In Guichan there are a number of implementations of the Input interface found in back end libraries. There is an Allegro implementation, a HGE implementation, an OpenLayer implementation and a SDL implementation. Most of the implementations need only to be instantiated and then passed to the Gui object and all is fine. The exception is the SDL implementation which relies on the end user supplying the SDLInput object with user input. Here is an example of how to use the SDLInput:

SDLInput* input;

void foo()
{
    while(SDL_PollEvent(&event))
    {
        input->pushInput(event);
    }
}

The SDLInput implementation also needs a couple of settings in order to work properly.

SDL_EnableUNICODE(1);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

The reason input has to be supplied to the SDLInput implementation is that Guichan is designed to take over your application as little as possible. By pushing input the end user is in charge of the whole input queue, not Guichan. In Allegro, OpenLayer and HGE, user input accessed from a global state variables, therefore there is no need to supply those Input implementations with user input as Guichan can access user input information without interfering with the end user.

Image and ImageLoader

Image and ImageLoader are interfaces in Guichan used to load an use images in a platform independent way. The relation between Image and ImageLoader is quite simple, the ImageLoader creates Images. There are a number of implementations of the Image and the ImageLoader interface found in back end libraries. There is an Allegro implementation, a HGE implementation, an OpenGL SDL implementation, an OpenLayer implementation and a SDL implementation (the reason there is no pure OpenGL implementation is that OpenGL lacks the ability to load images).

To be able to load images in Guichan an implementation of ImageLoader needs to be provided to the abstract class Image which is done with the static function Image::setImageLoader. Loading images are also done with a static function, Image::load.

void foo()
{
    Image::setImageLoader(imageLoader);
}

void bar()
{
    Image* image = Image::load("my-image.bmp");
}

When the AllegroImageLoader is used an AllegroImage is instantiated and returned when load is called, when the SDLImageLoader is used an SDLImage is instantiated and returned when load is called. End users normally don't have to bother with the implementation of Image an ImageLoader returns as all implementations inherit from the Image interface.

When loading images the colour 0xff00ff, also known as magic pink, will always be considered transparent.

Fonts

Font is an interface in Guichan used in Guichan to display text when drawing. There are a number of implementations of the Font interface found in the core library, in back end libraries and in the add on directory of the source. The implementations found in the core library are platform and back end independent, they are called DefaultFont and ImageFont. A font can be provided to Guichan as a global font. A global font will be used by a widget if no font has been provided to the widget.

Font* font;

void foo()
{
    Widget::setGlobalFont(font);
}

A font can also be provided explicitly to a widget.

Font* font
Widget* widget;

void foo()
{
    widget->setFont(font);    
}

DefaultFont is the font used when no font has been provided to Guichan. It can only display rectangles and it exists only as a fail safe.

ImageFont is a font that uses an image containing glyphs to display text. Each glyph in the image should be separated by a certain colour specified in the (0,0) pixel in the image called the separation colour. The width of the space character is specified in the image by a blank glyph. When instantiating an ImageFont the image should be provided along with a string containing the glyphs in the image in the exact order they appear in the image. The glyphs in the image doesn't have to be in one row, rows may be created by separating rows with the separation colour.

Example of an image for ImageFont that uses two rows. Note first blank glyph, it specifies the width of the space character.
Example of an image for ImageFont that uses two rows. Note first blank glyph, it specifies the width of the space character.
Font* font = new gcn::ImageFont();
gcn::ImageFont("image_with_font.bmp", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
Widget::setGlobalFont(font);
Personal tools
community