1 /*
2  *    Example program for the Allegro library, by Eric Botcazou.
3  *
4  *    This program demonstrates the use of the 16-bit Unicode text
5  *    encoding format with Allegro. The example displays a message
6  *    translated to different languages scrolling on the screen
7  *    using an external font containing the required characters to
8  *    display those messages.
9  *
10  *    Note how the Allegro unicode string functions resemble the
11  *    functions you can find in the standard C library, only these
12  *    handle Unicode on all platforms.
13  */
14 
15 
16 #include <stdlib.h>
17 #include <allegro.h>
18 
19 #define DATAFILE_NAME   "unifont.dat"
20 
21 #define NLANGUAGES 12
22 
23 
24 /* Animation timer. */
25 volatile int ticks = 0;
ticker(void)26 void ticker(void)
27 {
28     ticks++;
29 }
30 
31 #if defined ALLEGRO_LITTLE_ENDIAN
32 
33 /* UTF-16LE */
34 char message_en[] = "\x57\x00\x65\x00\x6c\x00\x63\x00\x6f\x00\x6d\x00\x65\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x00\x00";
35 
36 char message_fr[] = "\x42\x00\x69\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x75\x00\x65\x00\x20\x00\xE0\x00\x20\x00\x00\x00";
37 
38 char message_es[] = "\x42\x00\x69\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x69\x00\x64\x00\x6f\x00\x20\x00\x61\x00\x20\x00\x00\x00";
39 
40 char message_it[] = "\x42\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x75\x00\x74\x00\x69\x00\x20\x00\x61\x00\x64\x00\x20\x00\x00\x00";
41 
42 char message_el[] = "\x9A\x03\xB1\x03\xBB\x03\xCE\x03\xC2\x03\x20\x00\xAE\x03\xC1\x03\xB8\x03\xB1\x03\xC4\x03\xB5\x03\x20\x00\xC3\x03\xC4\x03\xBF\x03\x20\x00\x00\x00";
43 
44 char message_ru[] = "\x14\x04\x3e\x04\x31\x04\x40\x04\x3e\x04\x20\x00\x3f\x04\x3e\x04\x36\x04\x30\x04\x3b\x04\x3e\x04\x32\x04\x30\x04\x42\x04\x4c\x04\x20\x00\x32\x04\x20\x00\x00\x00";
45 
46 char message_he[] = "\x20\x00\xDC\x05\xD0\x05\x20\x00\xDD\x05\xD9\x05\xD0\x05\xD1\x05\xD4\x05\x20\x00\xDD\x05\xD9\x05\xDB\x05\xD5\x05\xE8\x05\xD1\x05\x00\x00";
47 
48 char message_ja[] = "\x78\x30\x88\x30\x46\x30\x53\x30\x5d\x30\x00\x00";
49 
50 char message_ka[] = "\x20\x00\xa8\x0C\xbf\x0C\xae\x0C\x97\x0C\xc6\x0C\x20\x00\xb8\x0C\xc1\x0C\xb8\x0C\xcd\x0C\xb5\x0C\xbe\x0C\x97\x0C\xa4\x0C";
51 
52 char message_ta[] = "\x20\x00\x89\x0B\x99\x0B\x82\x0B\x95\x0B\xC8\x0B\xB3\x0B\x20\x00\xB5\x0B\xB0\x0B\xC7\x0B\xB5\x0B\xB1\x0B\x82\x0B\x95\x0B\xBF\x0B\xB1\x0B\xA5\x0B\x00\x00";
53 
54 char message_zh[] = "\x22\x6b\xCE\x8F\x7F\x4f\x28\x75\x20\x00\x00\x00";
55 
56 char message_de[] = "\x57\x00\x69\x00\x6c\x00\x6c\x00\x6b\x00\x6f\x00\x6d\x00\x6d\x00\x65\x00\x6e\x00\x20\x00\x62\x00\x65\x00\x69\x00\x20\x00\x00\x00";
57 
58 char allegro_str[] = "\x41\x00\x6c\x00\x6c\x00\x65\x00\x67\x00\x72\x00\x6f\x00\x00\x00";
59 
60 #elif defined ALLEGRO_BIG_ENDIAN
61 
62 /* UTF-16BE */
63 char message_en[] = "\x00\x57\x00\x65\x00\x6c\x00\x63\x00\x6f\x00\x6d\x00\x65\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x00";
64 
65 char message_fr[] = "\x00\x42\x00\x69\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x75\x00\x65\x00\x20\x00\xE0\x00\x20\x00\x00";
66 
67 char message_es[] = "\x00\x42\x00\x69\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x69\x00\x64\x00\x6f\x00\x20\x00\x61\x00\x20\x00\x00";
68 
69 char message_it[] = "\x00\x42\x00\x65\x00\x6e\x00\x76\x00\x65\x00\x6e\x00\x75\x00\x74\x00\x69\x00\x20\x00\x61\x00\x64\x00\x20\x00\x00";
70 
71 char message_el[] = "\x03\x9A\x03\xB1\x03\xBB\x03\xCE\x03\xC2\x00\x20\x03\xAE\x03\xC1\x03\xB8\x03\xB1\x03\xC4\x03\xB5\x00\x20\x03\xC3\x03\xC4\x03\xBF\x00\x20\x00\x00";
72 
73 char message_ru[] = "\x04\x14\x04\x3e\x04\x31\x04\x40\x04\x3e\x00\x20\x04\x3f\x04\x3e\x04\x36\x04\x30\x04\x3b\x04\x3e\x04\x32\x04\x30\x04\x42\x04\x4c\x00\x20\x04\x32\x00\x20\x00\x00";
74 
75 char message_he[] = "\x00\x20\x05\xDC\x05\xD0\x00\x20\x05\xDD\x05\xD9\x05\xD0\x05\xD1\x05\xD4\x00\x20\x05\xDD\x05\xD9\x05\xDB\x05\xD5\x05\xE8\x05\xD1\x00\x00";
76 
77 char message_ja[] = "\x30\x78\x30\x88\x30\x46\x30\x53\x30\x5d\x00\x00";
78 
79 char message_ka[] = "\x20\x00\x0C\xa8\x0C\xbf\x0C\xae\x0C\x97\x0C\xc6\x20\x00\x0C\xb8\x0C\xc1\x0C\xb8\x0C\xcd\x0C\xb5\x0C\xbe\x0C\x97\xa4\x0C";
80 
81 char message_ta[] = "\x00\x20\x0B\x89\x0B\x99\x0B\x82\x0B\x95\x0B\xC8\x0B\xB3\x00\x20\x0B\xB5\x0B\xB0\x0B\xC7\x0B\xB5\x0B\xB1\x0B\x82\x0B\x95\x0B\xBF\x0B\xB1\x0B\xA5\x00\x00";
82 
83 char message_zh[] = "\x6b\x22\x8F\xCE\x4f\x7F\x75\x28\x00\x20\x00\x00";
84 
85 char message_de[] = "\x00\x57\x00\x69\x00\x6c\x00\x6c\x00\x6b\x00\x6f\x00\x6d\x00\x6d\x00\x65\x00\x6e\x00\x20\x00\x62\x00\x65\x00\x69\x00\x20\x00\x00";
86 
87 char allegro_str[] = "\x00\x41\x00\x6c\x00\x6c\x00\x65\x00\x67\x00\x72\x00\x6f\x00\x00";
88 
89 #elif !defined SCAN_DEPEND
90    #error endianess not defined
91 #endif
92 
93 
94 struct MESSAGE {
95    char *data, *str;
96    int prefix_allegro;
97    int dx, dy;
98    int x, y, w, h;
99    int c;
100 };
101 
102 
103 struct MESSAGE message[] = { {message_en, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
104                              {message_fr, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
105                              {message_es, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
106                              {message_it, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
107                              {message_el, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
108                              {message_ru, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
109                              {message_he, NULL, TRUE,   1,  0, 0, 0, 0, 0, 0},
110                              {message_ja, NULL, TRUE,  -1,  0, 0, 0, 0, 0, 0},
111                              {message_ka, NULL, TRUE,  -1,  0, 0, 0, 0, 0, 0},
112                              {message_ta, NULL, TRUE,  -1,  0, 0, 0, 0, 0, 0},
113                              {message_zh, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0},
114                              {message_de, NULL, FALSE, -1,  0, 0, 0, 0, 0, 0}
115 };
116 
117 
overlap(int i,int j,int pad)118 static int overlap(int i, int j, int pad)
119 {
120    return message[i].x - pad < message[j].x + message[j].w + pad &&
121       message[j].x - pad < message[i].x + message[i].w + pad &&
122       message[i].y - pad < message[j].y + message[j].h + pad &&
123       message[j].y - pad < message[i].y + message[i].h + pad;
124 }
125 
126 
main(int argc,char * argv[])127 int main(int argc, char *argv[])
128 {
129    DATAFILE *data;
130    FONT *f;
131    BITMAP *buffer;
132    int i, j, k, height;
133    char buf[256], tmp[256], tmp2[256];
134    int counter = 0, drawn = 0;
135    int scroll_w, scroll_h;
136    int background_color;
137 
138    /* set the text encoding format BEFORE initializing the library */
139    set_uformat(U_UNICODE);
140 
141    /*  past this point, every string that we pass to or retrieve
142     *  from any Allegro API call must be in 16-bit Unicode format
143     */
144 
145    srand(time(NULL));
146    if (allegro_init() != 0)
147       return 1;
148    install_keyboard();
149    install_timer();
150 
151    /* load the datafile containing the Unicode font */
152    replace_filename(buf, uconvert_ascii(argv[0], tmp), uconvert_ascii(DATAFILE_NAME, tmp2), sizeof(buf));
153    data = load_datafile(buf);
154    if (!data) {
155       allegro_message(uconvert_ascii("Unable to load %s\n", tmp), buf);
156       return -1;
157    }
158 
159    /* set the graphics mode */
160    if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
161       if (set_gfx_mode(GFX_SAFE, 640, 480, 0, 0) != 0) {
162 	 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
163 	 allegro_message(uconvert_ascii("Unable to set any graphic mode\n%s\n", tmp), allegro_error);
164 	 return 1;
165       }
166    }
167 
168    /* set the window title for windowed modes */
169    set_window_title(uconvert_ascii("Unicode example program", tmp));
170 
171    /* create a buffer for drawing */
172    buffer = create_bitmap(SCREEN_W, SCREEN_H);
173 
174    /* get a handle to the Unicode font */
175    f = data[0].dat;
176    height = text_height(f);
177 
178    /* The are for the text messages. If it gets too crowded once we have more
179     * languages, this can be increased.
180     */
181    scroll_w = SCREEN_W * 2;
182    scroll_h = SCREEN_H + height;
183 
184    /* one of the bright colors in the default palette */
185    background_color = 56 + AL_RAND() % 48;
186 
187    /* prepare the messages */
188    for (i = 0; i < NLANGUAGES; i++) {
189 
190       /* the regular Standard C string manipulation functions don't work
191        * with 16-bit Unicode, so we use the Allegro Unicode API
192        */
193       message[i].str = malloc(ustrsize(message[i].data) + ustrsizez(allegro_str));
194 
195       if (message[i].prefix_allegro) {
196          ustrcpy(message[i].str, allegro_str);
197          ustrcat(message[i].str, message[i].data);
198       }
199       else {
200          ustrcpy(message[i].str, message[i].data);
201          ustrcat(message[i].str, allegro_str);
202       }
203 
204       message[i].w = text_length(f, message[i].str);
205       message[i].h = text_height(f);
206 
207       /* one of the dark colors in the default palette */
208       message[i].c = 104 + AL_RAND() % 144;
209 
210       message[i].dx *= 1 + AL_RAND() % 4;
211       message[i].dy = AL_RAND() % 3 - 1;
212 
213       /* find not-overlapped position, try 1000 times */
214       for (k = 0; k < 1000; k++) {
215          message[i].x = AL_RAND() % scroll_w;
216          /* make sure the message is not sliced by a screen edge */
217          message[i].y = 10 + AL_RAND() % (SCREEN_H - height - 20);
218          for (j = 0; j < i; j++) {
219             if (overlap(i, j, 10))
220                break;
221          }
222          if (j == i)
223             break;
224       }
225    }
226 
227    install_int_ex(ticker, BPS_TO_TIMER(30));
228    /* do the scrolling */
229    while (!keypressed()) {
230       /* Animation. */
231       while (counter <= ticks) {
232          for (i = 0; i < NLANGUAGES; i++) {
233             message[i].x += message[i].dx;
234             if (message[i].x >= scroll_w)
235                message[i].x -= scroll_w;
236             if (message[i].x < 0)
237                message[i].x += scroll_w;
238             message[i].y += message[i].dy;
239             if (message[i].y >= scroll_h)
240                message[i].y -= scroll_h;
241             if (message[i].y < 0)
242                message[i].y += scroll_h;
243          }
244          counter++;
245       }
246 
247       /* Draw current frame. */
248       if (drawn < counter) {
249          clear_to_color(buffer, background_color);
250          for (i = 0; i < NLANGUAGES; i++) {
251             char *str = message[i].str;
252             int x = message[i].x;
253             int y = message[i].y;
254             int c = message[i].c;
255             /* draw it 4 times to get the wrap-around effect */
256             textout_ex(buffer, f, str, x, y, c, -1);
257             textout_ex(buffer, f, str, x - scroll_w, y, c, -1);
258             textout_ex(buffer, f, str, x, y - scroll_h, c, -1);
259             textout_ex(buffer, f, str, x - scroll_w, y - scroll_h, c, -1);
260          }
261          blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
262          drawn = counter;
263       }
264       else {
265          rest(10); /* We are too fast, give time to the OS. */
266       }
267    }
268 
269    destroy_bitmap(buffer);
270 
271    unload_datafile(data);
272 
273    return 0;
274 }
275 END_OF_MAIN()
276