Allegro Snippets

C++

A Loading Bar for Allegro 5

Allegro is a games programming library, which offers a very vast range of games development routines, and in my mind is absolutely brilliant. This is a loading bar that I wrote using, it takes an array of files, a function pointer to a draw function, and a function pointer to a load function, for each file the code will work out the size, then call the load function passing that file’s path to it, the load function being a users function can do whatever it likes with this data, once it’s done the progress is worked out as a percentage of the total file size which is then passed to the draw function (as a value between 0.0 and 1.0) which again can be used to draw whatever you want.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
    very easy to use pass it an array of char *
    and the number of files
    the draw function is in the form:
    void draw(float perc);
    The perc value is from 0.0f to 1.0f
    and the load is:
    void load(const char *fname);
 
    what you do with the passed information is...
    ... well... between you and God :-P
*/
long al_loading_bar(char *filelist[],int number_of_files,void (*drawcallback)(float percentage),void (loadcallback)(const char *filename))
{
    // Used for looping through the passed files.
    int current_file_counter;
    // Represents the size of all files to load.
    unsigned long total_loading_size = 0;
    // Represents how much has been loaded already.
    unsigned long currently_loaded_size = 0;
    // The Size of the Current File
    unsigned long current_file_size;
    // An entry in the allegro file system.
    ALLEGRO_FS_ENTRY *file_entry;
 
    // Loop through the files, getting there size in bytes and adding them to the total size.
    for(current_file_counter = 0;current_file_counter < number_of_files;current_file_counter+=1)
    {
        file_entry = al_create_fs_entry(filelist[current_file_counter]);
        total_loading_size += (long)al_get_fs_entry_size(file_entry);
        al_destroy_fs_entry(file_entry);
    }
 
    // Loop through the files again, and this time call the load and drawing code.
    for(current_file_counter = 0;current_file_counter < number_of_files;current_file_counter+=1)
    {
        // Call the draw function, always drawing before the new file size is added.
        drawcallback((float)currently_loaded_size / (float)total_loading_size);
        // Get the filename from the list.
        file_entry = al_create_fs_entry(filelist[current_file_counter]);
        // Get the current file's size in bytes.
        current_file_size = (long)al_get_fs_entry_size(file_entry);
        // Call the load function passing it the filename.
        loadcallback(filelist[current_file_counter]);
        // Once loaded add the file size to the loaded list.
        currently_loaded_size+=current_file_size;
        // Clean up.
        al_destroy_fs_entry(file_entry);
    }
 
    // Draw the bar at 100 % to make it look nice :D
    drawcallback(1.0f);
 
    // Return the total loading size... just incase you were interested.
    return(total_loading_size);
}

Replacement for_each_file in allegro 5

 

Allegro 5 was a big improvement from Allegro 4 in terms of feature support and enhanced it’s cross platform capacities. The system has some transparent file system routines which are brilliant, but there is one thing I found missing from allegro 5, and that’s a simple way to call one function for a whole group of files. In allegro 4 this function was called for_each_file (and lately for_ex_file_ex), now you can achieve the same effect through a series of function calls, but in the interest of simplicity I have created a handy 1 stop function. Please note that the passed in extension list is seperated by ‘|’ and should include the ‘.’ before the extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
int al_for_each_file(char *start_dir,bool include_directory,char *ext,int (*callback)(const char *filename,bool is_dir))
{
// Create an Allegro file system reference to the starting directory.
ALLEGRO_FS_ENTRY* dir = al_create_fs_entry(start_dir);
// A char copy or the passed char * list of extensions to include.
char ExtList[255];
// A char holding the extension only of each file read.
char TheFileExt[255];
// An array of 12 strings used to store the extension we are including
char Ext[10][12];
// The pointer to a char used to tokenize the passed extension list
char *pch;
// Used to loop though all the extensions for comparison
int ExtLoop;
// A count of how many extensions are included < 10
int ExtCount = 0;
// An individual file in our File System
ALLEGRO_FS_ENTRY* file;
// An Allegro Path for the above file.
ALLEGRO_PATH *filepath;
// Counts how many files have been passed.
int FileCount = 0;
 
// Sort out the extension list, and make sure there is no data in it already.
strcpy(ExtList,ext);
for(ExtCount; ExtCount < 10;ExtCount+=1)
{
strcpy(Ext[ExtCount],"");
}
 
ExtCount = 0;
 
// Tokanize our list to get the first element
pch = strtok(ExtList,"|");
// Move through the list storing the next extension in the next available array slot.
do
{
strcpy(Ext[ExtCount],pch);
strcat(Ext[ExtCount],"");
pch = strtok (NULL, "|");
ExtCount+=1;
}while(pch!=NULL && ExtCount < 10);
// Clean-up.
delete(pch);
 
// Open our starting directory.
if(al_open_directory(dir))
{
// Read in a file
while(file = al_read_directory(dir))
{
// If 'file' is really a directory
if(al_get_fs_entry_mode(file) & ALLEGRO_FILEMODE_ISDIR)
{
// And we're including directories
if(include_directory == true)
{
// activate callback function setting directory flag to true.
callback(al_get_fs_entry_name(file),true);
FileCount+=1;
}
}
else
{
// Get a path of the file and find it's extension.
filepath = al_create_path(al_get_fs_entry_name(file));
strcpy(TheFileExt,al_get_path_extension(filepath));
// Loop through extensions list.
for(ExtLoop = 0;ExtLoop < ExtCount;ExtLoop+=1)
{
// If one matches
if(strcmp(TheFileExt,Ext[ExtLoop]) == 0)
{
// activate call back, setting directory flag to false.
callback(al_get_fs_entry_name(file),false);
FileCount+=1;
}
 
}
// Clean up
al_destroy_path(filepath);
}
// Clean up
al_destroy_fs_entry(file);
}
}
// Clean up
al_destroy_fs_entry(dir);
// Return number of files and Fin.
return(FileCount);
}

A wrapped text function for allegro5

Below is the code for a wrapped text function for Allegro5.

The three features are:

  1. Three different text alignment modes (Left, Centre, Right)
  2. The function returns the height of the text, which would allow you to draw a box of exactly the right height (in pixels) to contain the text.
  3. It can support the ‘\n’ character to allow for basic formatting of the text.

It should be quite self explanatory, I’ve commented it throughout but here is a list of the variables you pass to the function:

  • ‘af’ is the ALLEGRO_FONT that you want the text drawn in.
  • ‘atext’ is the text itself.
  • ‘fc’ is an ALLEGRO_COLOR representing the colour you want it the text to be drawn in.
  • ‘x1′ and ‘y1′ are the X and Y positions of the top left corner of the first line of text (in pixels)
  • ‘width’ is how far you want the text to go along the X-axis before it wraps.
  • ‘flags’ are either: ALLEGRO_ALIGN_LEFT / ALLEGRO_ALIGN_RIGHT / ALLEGRO_ALIGN_CENTRE
  • ‘draw’ tells the function whether to draw the text, if not it will simply return the height of the text. Therefore to draw a box in the background you would:
  1. Call DrawWrappedText but pass ‘draw’ = false.
  2. Use the returned height to draw your box at X1 – (border), Y1 -(border), X1+width+(border),Y1 + height + (border)
  3. Call DrawWrappedText again passing ‘draw’ = true.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
int DrawWrappedText(ALLEGRO_FONT *af,char atext[1024],ALLEGRO_COLOR fc, int x1, int y1, int width, int flags,bool draw)
{
char stext[1024]; // Copy of the passed text.
char * pch; // A pointer to each word.
char word[255]; // A string containing the word (for convienence)
char breakchar[12]; // Contains the break line character "\n "
char Lines[40][1024]; // A lovely array of strings to hold all the lines (40 max atm)
char TempLine[1024]; // Holds the string data of the current line only.
int CurrentLine = 0; // Counts which line we are currently using.
int q; // Used for loops
 
// Setup our strings
strcpy(stext,atext);
strcpy(breakchar,"\n ");
strcpy(TempLine,"");
for(q = 0;q < 40;q+=1)
{
sprintf(Lines[q],"");
}
//-------------------- Code Begins
 
pch = strtok (stext," ");                               // Get the first word.
do
{
strcpy(word,"");                                  // Truncate the string, to ensure there's no crazy stuff in there from memory.
sprintf(word,"%s ",pch);
sprintf(TempLine,"%s%s",TempLine,word);             // Append the word to the end of TempLine
// This code checks for the new line character.
if(strcmp(word,breakchar) == 0)
{
CurrentLine+=1;                                 // Move down a Line
strcpy(TempLine,"");                            // Clear the tempstring
}
else
{
if(al_get_text_width(af,TempLine) >= (width))   // Check if text is larger than the area.
{
strcpy(TempLine,word);                      // clear the templine and add the word to it.
CurrentLine+=1;                             // Move to the next line.
}
if(CurrentLine < 40)
{
strcat(Lines[CurrentLine],word);                // Append the word to whatever line we are currently on.
}
}
pch = strtok (NULL, " ");                           // Get the next word.
}while (pch != NULL);
// ---------------------------------- Time to draw.
if(draw == true)                                       //Check whether we are actually drawing the text.
{
for(q = 0;q <=CurrentLine;q+=1)                     // Move through each line and draw according to the passed flags.
{
if(flags == ALLEGRO_ALIGN_LEFT)
al_draw_text(af,fc, x1, y1 + (q * al_get_font_line_height(af)), ALLEGRO_ALIGN_LEFT,Lines[q]);
if(flags == ALLEGRO_ALIGN_CENTRE)
al_draw_text(af,fc, x1 + (width/2), y1 + (q * al_get_font_line_height(af)), ALLEGRO_ALIGN_CENTRE,Lines[q]);
if(flags == ALLEGRO_ALIGN_RIGHT)
al_draw_text(af,fc, x1 + width, y1 + (q * al_get_font_line_height(af)), ALLEGRO_ALIGN_RIGHT,Lines[q]);
}
 
}
return((CurrentLine+1) * al_get_font_line_height(af));  // Return the actual height of the text in pixels.
}