Introduction

Welcome to Allegro 5!

Before to start, be sure you have read the README file. Then you can read the Getting Started section and go to the All units list to start using Allegro.pas.

  1. Getting started
    1. Structure of the library and its addons
    2. Initialisation
    3. Opening a window
    4. Displaying an image
    5. Changing the drawing target
    6. Event queues and input
    7. Displaying some text
    8. Drawing primitives
    9. Blending
    10. Sound
    11. Unstable API
  2. Config files
  3. Displays
  4. Events
  5. Alternative file streams
  6. Keyboard
    1. Key codes
    2. Keyboard modifier flags
  7. Transformations
  8. Threads

Getting started

This short guide should point you at the parts of the API that you'll want to know about first. It's not a tutorial, as there isn't much discussion, only links into the manual. The rest you'll have to discover for yourself. Read the examples, and ask questions at Pascal Game Development, Lazarus/FPC forums or Allegro.cc.

Structure of the library and its addons

Allegro 5.0 is divided into a core library and multiple addons. The addons are bundled together and built at the same time as the core, but they are distinct and kept in separate libraries. The core doesn't depend on anything in the addons, but addons may depend on the core and other addons and additional third party libraries.

Here are the addons and their dependencies:

allegro_main -> allegro

allegro_image -> allegro
allegro_primitives -> allegro
allegro_color -> allegro

allegro_font -> allegro
allegro_ttf -> allegro_font -> allegro

allegro_audio -> allegro
allegro_acodec -> allegro_audio -> allegro

allegro_memfile -> allegro
allegro_physfs -> allegro

allegro_native_dialog -> allegro

The unit for the core library is Allegro5. The units for the addons are named al5image, al5font, etc. The allegro_main addon does not have an unit file.

Initialisation

Before using Allegro you must call al_init. Some addons have their own initialisation, e.g. al_init_image_addon, al_init_font_addon, al_init_ttf_addon.

To receive input, you need to initialise some subsystems like al_install_keyboard, al_install_mouse, al_install_joystick.

Opening a window

al_create_display will open a window and return an ALLEGRO_DISPLAYptr.

To clear the display, call al_clear_to_color. Use al_map_rgba or al_map_rgba_f to obtain an ALLEGRO_COLOR parameter.

Drawing operations are performed on a backbuffer. To make the operations visible, call al_flip_display.

You can get more information about displays in the Displays section.

Displaying an image

To load an image from disk, you need to have initialised the image I/O addon with al_init_image_addon. Then use al_load_bitmap, which returns an ALLEGRO_BITMAPptr.

Use al_draw_bitmap, al_draw_scaled_bitmap or al_draw_scaled_rotated_bitmap to draw the image to the backbuffer. Remember to call al_flip_display.

Changing the drawing target

Notice that al_clear_to_color and al_draw_bitmap didn't take destination parameters: the destination is implicit. Allegro remembers the current "target bitmap" for the current thread. To change the target bitmap, call al_set_target_bitmap.

The backbuffer of the display is also a bitmap. You can get it with al_get_backbuffer and then restore it as the target bitmap.

Other bitmaps can be created with al_create_bitmap, with options which can be adjusted with al_set_new_bitmap_flags and al_set_new_bitmap_format.

Event queues and input

Input comes from multiple sources: keyboard, mouse, joystick, timers, etc. Event queues aggregate events from all these sources, then you can query the queue for events.

Create an event queue with al_create_event_queue, then tell input sources to place new events into that queue using al_register_event_source. The usual input event sources can be retrieved with al_get_keyboard_event_source, al_get_mouse_event_source and al_get_joystick_event_source.

Events can be retrieved with al_wait_for_event or al_get_next_event. Check the event type and other fields of ALLEGRO_EVENT to react to the input.

Displays are also event sources, which emit events when they are closed or resized. To get these events you'll need to set some special flags with al_set_new_display_flags before creating the display, then register the display with an event queue. When you get a resize event, call al_acknowledge_resize.

Timers are event sources which "tick" periodically, causing an event to be inserted into the queues that the timer is registered with. Create some with al_create_timer.

al_get_time and al_rest are more direct ways to deal with time.

Displaying some text

To display some text, initialise the image and font addons with al_init_image_addon and al_init_font_addon, then load a bitmap font with al_load_font. Use al_draw_text.

For TrueType fonts, you'll need to initialise the TTF font addon with al_init_ttf_addon and load a TTF font with al_load_ttf_font.

Note that Allegro uses AL_STR (defined as ANSISTRING), so it will not manage UNICODESTRING or WIDESTRING correctly. That may conflict with some RTL functions and procedures (specially in modern Delphi), unit al5strings defines functions and procedures to reduce such conflicts.

Drawing primitives

The primitives addon provides some handy routines to draw lines (al_draw_line), rectangles (al_draw_rectangle), circles (al_draw_circle), etc.

Blending

To draw translucent or tinted images or primitives, change the blender state with al_set_blender.

As with al_set_target_bitmap, this changes Allegro's internal state (for the current thread). Often you'll want to save some part of the state and restore it later. The functions al_store_state and al_restore_state provide a convenient way to do that.

Sound

Use al_install_audio to initialize sound. To load any sample formats, you will need to initialise the acodec addon with al_init_acodec_addon.

After that, you can simply use al_reserve_samples and pass the number of sound effects typically playing at the same time. Then load your sound effects with al_load_sample and play them with al_play_sample. To stream large pieces of music from disk, you can use al_load_audio_stream so the whole piece will not have to be pre-loaded into memory.

If the above sounds too simple and you can't help but think about clipping and latency issues, don't worry. Allegro gives you full control over how much or little you want its sound system to do. The al_reserve_samples function mentioned above only sets up a default mixer and a number of sample instances but you don't need to use it.

Instead, to get a "direct connection" to the sound system you would use an ALLEGRO_VOICEptr (but depending on the platform only one such voice is guaranteed to be available and it might require a specific format of audio data). Therefore all sound can be first routed through an ALLEGRO_MIXERptr which is connected to such a voice (or another mixer) and will mix together all sample data fed to it.

You can then directly stream real-time sample data to a mixer or a voice using an ALLEGRO_AUDIO_STREAMptr or play complete sounds using an ALLEGRO_SAMPLE_INSTANCEptr. The latter simply points to an ALLEGRO_SAMPLEptr and will stream it for you.

Unstable API

Some of the original Allegro's API is marked as unstable, which means that future versions of Allegro it may change or even be removed entirely! That API isn't included in the Allegro.pas wrappers.

Config files

Allegro supports reading and writing of configuration files with a simple, INI file-like format. These files are fully compatible with the TIniFile objects defined by Delphi and Free Pascal. You can use TIniFile, but you should use Allegro's config procedures if you're writting your own Allegro add-on.

A configuration file consists of key-value pairs separated by newlines. Keys are separated from values by an equals sign (=). All whitespace before the key, after the value and immediately adjacent to the equals sign is ignored. Keys and values may have whitespace characters within them. Keys do not need to be unique, but all but the last one are ignored.

The hash (#) character is used a comment when it is the first non-whitespace character on the line. All characters following that character are ignored to the end of the line. The hash character anywhere else on the line has no special significance.

Key-value pairs can be optionally grouped into sections, which are declared by surrounding a section name with square brackets ([ and ]) on a single line. Whitespace before the opening bracket is ignored. All characters after the trailing bracket are also ignored.

All key-value pairs that follow a section declaration belong to the last declared section. Key-value pairs that don't follow any section declarations belong to the global section. Sections do not nest.

Here is an example configuration file:

#  Monster description
monster name = Allegro Developer

[weapon 0]
damage = 443

[weapon 1]
damage = 503

It can then be accessed like this (make sure to check for errors in an actual program):

VAR
  Cfg: ALLEGRO_CONFIGptr;
BEGIN
  cfg := al_load_config_file ('test.cfg');
  WriteLn (al_get_config_value (Cfg, '', 'monster name')); { Prints: Allegro Developer }
  WriteLn (al_get_config_value (Cfg, 'weapon 0', 'damage')); { Prints: 443 }
  WriteLn (al_get_config_value (Cfg, 'weapon 1', 'damage')); { Prints: 503 }
  al_destroy_config (Cfg)
END.

See also: al_load_config_file

Displays

All drawing operations end up being visible on a display which is the same as a window in windowed environments. Thus, before anything is displayed, a display needs to be created.

Before creating a display with al_create_display, flags and options can be set with al_set_new_display_flags and al_set_new_display_option. For example, you can enable the use of shaders or choose between the OpenGL and Direct3D backends (on platforms that support both) with al_set_new_display_flags. Display options are rather optional settings that do not affect Allegro itself, e.g. they allow you to specify whether you want a depth buffer or enable multisampling.

The actual properties of a display that has been successfully created can be queried via al_get_display_option, al_get_display_flags, al_get_display_width etc. Note that you can query some additional read-only properties such as the maximum allowed bitmap (i.e. texture) size via al_get_display_option.

Each display has a backbuffer associated to it which is the default target for any drawing operations. In order to make visible what has been drawn previously, you have to to call al_flip_display. Note that it is generally advisable to redraw the whole screen (or clear it in advance) to avoid artefacts of uninitialised memory becoming visible with some drivers.

You don't have to use Allegro's drawing routines, however: since creating a display implies the creation of an OpenGL context or Direct3D device respectively, you can use these APIs directly if you prefer to do so. Allegro provides integration for both (see the OpenGL / Direct3D sections), so you can retrieve the underlying textures of ALLEGRO_BITMAPs, for example.

In order to write a well-behaved application, it is necessary to remember that displays will also inform you about important events via their event sources.

Events

Events are generated by event sources. Most notably, each of the input subsystems provides an event source, but also timers, displays, and audio streams will generate events.

Event sources are registered to event queues which aggregate events from multiple sources. A single event source can also be registered to multiple event queues.

Event queues can then be queried for events. In particular, it is possible to wait until events become available in order to save CPU time. You can combine this with timers to make your main-loop run at a specific speed without wasting CPU time or missing events.

In addition to the predefined event types, Allegro also allows for user-defined events that can be generated by user-defined event sources.

The appropriate reaction to an event is determined by examining the fields of the ALLEGRO_EVENT union according to the event type.

In addition to the events sent by Allegro core, there's also events send by the addons, see al5audio and al5video.

Alternative file streams

By default, the Allegro file I/O routines use the C library I/O routines, hence work with files on the local filesystem, but can be overridden so that you can read and write to other streams. For example, you can work with blocks of memory or sub-files inside .zip files.

There are two ways to get an ALLEGRO_FILEptr that doesn't use stdio. An addon library may provide a function that returns a new ALLEGRO_FILEptr directly, after which, all al_f* calls on that object will use overridden functions for that type of stream. Alternatively, al_set_new_file_interface changes which function will handle the following al_fopen calls for the current thread.

Keyboard

Key codes

The constant ALLEGRO_KEY_MAX is always one higher than the highest key code. So if you want to use the key code as array index you can do something like this:

VAR
  PressedKeys: ARRAY[0..ALLEGRO_KEY_MAX] OF BOOLEAN;
...
  PressedKeys[KeyCode] := TRUE;

These are the list of key codes used by Allegro, which are returned in the event.keyboard.keycode field of the ALLEGRO_KEY_DOWN and ALLEGRO_KEY_UP events and which you can pass to al_key_down:

ALLEGRO_KEY_A ... ALLEGRO_KEY_Z
ALLEGRO_KEY_0 ... ALLEGRO_KEY_9
ALLEGRO_KEY_PAD_0 ... ALLEGRO_KEY_PAD_9
ALLEGRO_KEY_F1 ... ALLEGRO_KEY_F12
ALLEGRO_KEY_ESCAPE
ALLEGRO_KEY_TILDE
ALLEGRO_KEY_MINUS
ALLEGRO_KEY_EQUALS
ALLEGRO_KEY_BACKSPACE
ALLEGRO_KEY_TAB
ALLEGRO_KEY_OPENBRACE
ALLEGRO_KEY_CLOSEBRACE
ALLEGRO_KEY_ENTER
ALLEGRO_KEY_SEMICOLON
ALLEGRO_KEY_QUOTE
ALLEGRO_KEY_BACKSLASH
ALLEGRO_KEY_BACKSLASH2
ALLEGRO_KEY_COMMA
ALLEGRO_KEY_FULLSTOP
ALLEGRO_KEY_SLASH
ALLEGRO_KEY_SPACE
ALLEGRO_KEY_INSERT
ALLEGRO_KEY_DELETE
ALLEGRO_KEY_HOME
ALLEGRO_KEY_END
ALLEGRO_KEY_PGUP
ALLEGRO_KEY_PGDN
ALLEGRO_KEY_LEFT
ALLEGRO_KEY_RIGHT
ALLEGRO_KEY_UP
ALLEGRO_KEY_DOWN
ALLEGRO_KEY_PAD_SLASH
ALLEGRO_KEY_PAD_ASTERISK
ALLEGRO_KEY_PAD_MINUS
ALLEGRO_KEY_PAD_PLUS
ALLEGRO_KEY_PAD_DELETE
ALLEGRO_KEY_PAD_ENTER
ALLEGRO_KEY_PRINTSCREEN
ALLEGRO_KEY_PAUSE
ALLEGRO_KEY_ABNT_C1
ALLEGRO_KEY_YEN
ALLEGRO_KEY_KANA
ALLEGRO_KEY_CONVERT
ALLEGRO_KEY_NOCONVERT
ALLEGRO_KEY_AT
ALLEGRO_KEY_CIRCUMFLEX
ALLEGRO_KEY_COLON2
ALLEGRO_KEY_KANJI
ALLEGRO_KEY_LSHIFT
ALLEGRO_KEY_RSHIFT
ALLEGRO_KEY_LCTRL
ALLEGRO_KEY_RCTRL
ALLEGRO_KEY_ALT
ALLEGRO_KEY_ALTGR
ALLEGRO_KEY_LWIN
ALLEGRO_KEY_RWIN
ALLEGRO_KEY_MENU
ALLEGRO_KEY_SCROLLLOCK
ALLEGRO_KEY_NUMLOCK
ALLEGRO_KEY_CAPSLOCK
ALLEGRO_KEY_PAD_EQUALS
ALLEGRO_KEY_BACKQUOTE
ALLEGRO_KEY_SEMICOLON2
ALLEGRO_KEY_COMMAND

(* Since: 5.1.1 *)
(* Android only for now *)
ALLEGRO_KEY_BACK

(* Since: 5.1.2 *)
(* Android only for now *)
ALLEGRO_KEY_VOLUME_UP
ALLEGRO_KEY_VOLUME_DOWN

(* Since: 5.1.6 *)
(* Android only for now *)
ALLEGRO_KEY_SEARCH
ALLEGRO_KEY_DPAD_CENTER
ALLEGRO_KEY_BUTTON_X
ALLEGRO_KEY_BUTTON_Y
ALLEGRO_KEY_DPAD_UP
ALLEGRO_KEY_DPAD_DOWN
ALLEGRO_KEY_DPAD_LEFT
ALLEGRO_KEY_DPAD_RIGHT
ALLEGRO_KEY_SELECT
ALLEGRO_KEY_START
ALLEGRO_KEY_L1
ALLEGRO_KEY_R1

Keyboard modifier flags

The event field keyboard.modifiers is a bitfield composed of these constants. These indicate the modifier keys which were pressed at the time a character was typed.

ALLEGRO_KEYMOD_SHIFT
ALLEGRO_KEYMOD_CTRL
ALLEGRO_KEYMOD_ALT
ALLEGRO_KEYMOD_LWIN
ALLEGRO_KEYMOD_RWIN
ALLEGRO_KEYMOD_MENU
ALLEGRO_KEYMOD_ALTGR
ALLEGRO_KEYMOD_COMMAND
ALLEGRO_KEYMOD_SCROLLLOCK
ALLEGRO_KEYMOD_NUMLOCK
ALLEGRO_KEYMOD_CAPSLOCK
ALLEGRO_KEYMOD_INALTSEQ
ALLEGRO_KEYMOD_ACCENT1
ALLEGRO_KEYMOD_ACCENT2
ALLEGRO_KEYMOD_ACCENT3
ALLEGRO_KEYMOD_ACCENT4

Transformations

Transformations allow you to transform the coordinates you use for drawing operations without additional overhead. Scaling, rotating, translating, and combinations of these are possible as well as using custom transformations. There are two types of transformations that you can set, 'regular' transformations and projection transformations. The projection transform is rarely used in 2D games, but is common in 3D games to set up the projection from the 3D world to the 2D screen. Typically, you would use the regular transform for non-projective types of transformations (that is, translations, rotations, scales, skews... i.e. transformations that are linear), while the projection transform will be used for setting up perspective and possibly more advanced effects. It is possible to do everything with just using the projection transformation (that is, you'd compose the projection transformation with the non-projection transformations that, e.g., move the camera in the world), but it is more convenient to use both for two reasons:

  • Regular transformations can be changed while the bitmap drawing is held (see al_hold_bitmap_drawing).

  • Regular transformations work with memory bitmaps.

As a result, if you're making a 2D game, it's best to leave the projection transformations at their default values.

Both types of transformations are set per target-bitmap, i.e. a change of the target bitmap will also change the active transformation.

Allegro provides convenience functions to construct transformations in 2D and 3D variants (the latter with a _3d suffix), so you don't have to deal with the underlying matrix algebra yourself.

The transformations are combined in the order of the function invocations. Thus to create a transformation that first rotates a point and then translates it, you would (starting with an identity transformation) call al_rotate_transform and then al_translate_transform. This approach is opposite of what OpenGL uses but similar to what Direct3D uses.

For those who know the matrix algebra going behind the scenes, what the transformation functions in Allegro do is "pre-multiply" the successive transformations. So, for example, if you have code that does:

al_identity_transform (T);

al_compose_transform (T, T1);
al_compose_transform (T, T2);
al_compose_transform (T, T3);
al_compose_transform (T, T4);

The resultant matrix multiplication expression will look like this:

T := T4 * T3 * T2 * T1

Since the point coordinate vector term will go on the right of that sequence of factors, the transformation that is called first, will also be applied first.

This means if you have code like this:

al_identity_transform (T1);
al_scale_transform (T1, 2, 2);

al_identity_transform (T2);
al_translate_transform (T2, 100, 0);

al_identity_transform (T);
al_compose_transform (T, T1);
al_compose_transform (T, T2);

al_use_transform (T);

it does exactly the same as:

al_identity_transform (T);
al_scale_transform (T, 2, 2);
al_translate_transform (T, 100, 0);
al_use_transform (T);

Threads

Allegro includes a simple cross-platform threading interfaces but unfortunatelly it doesn't work with Pascal, neither Free Pascal or Delphi.

Anyway Free Pascal and Delphi threading interface and their TThread class work perfectly so use it. See examples ex_threads and ex_threads2 to know how to use them.


Generated by PasDoc 0.15.0. Generated on 2024-11-10 15:15:06.