nuklear_allegro5.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. * Nuklear - 1.32.0 - public domain
  3. * no warrenty implied; use at your own risk.
  4. * authored from 2015-2016 by Micha Mettke
  5. */
  6. /*
  7. * ==============================================================
  8. *
  9. * API
  10. *
  11. * ===============================================================
  12. */
  13. #ifndef NK_ALLEGRO5_H_
  14. #define NK_ALLEGRO5_H_
  15. #include <string.h>
  16. #include <allegro5/allegro.h>
  17. #include <allegro5/allegro_image.h>
  18. #include <allegro5/allegro_primitives.h>
  19. #include <allegro5/allegro_font.h>
  20. #include <allegro5/allegro_ttf.h>
  21. typedef struct NkAllegro5Font NkAllegro5Font;
  22. NK_API struct nk_context* nk_allegro5_init(NkAllegro5Font *font, ALLEGRO_DISPLAY *dsp,
  23. unsigned int width, unsigned int height);
  24. NK_API void nk_allegro5_handle_event(ALLEGRO_EVENT *ev);
  25. NK_API void nk_allegro5_shutdown(void);
  26. NK_API void nk_allegro5_render(void);
  27. NK_API struct nk_image* nk_allegro5_create_image(const char* file_name);
  28. NK_API void nk_allegro5_del_image(struct nk_image* image);
  29. /* Fonts. We wrap normal allegro fonts in some nuklear book keeping */
  30. NK_API NkAllegro5Font* nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags);
  31. NK_API void nk_allegro5_font_del(NkAllegro5Font *font);
  32. NK_API void nk_allegro5_font_set_font(NkAllegro5Font *font);
  33. #endif
  34. /*
  35. * ==============================================================
  36. *
  37. * IMPLEMENTATION
  38. *
  39. * ===============================================================
  40. */
  41. #ifdef NK_ALLEGRO5_IMPLEMENTATION
  42. #ifndef NK_ALLEGRO5_TEXT_MAX
  43. #define NK_ALLEGRO5_TEXT_MAX 256
  44. #endif
  45. struct NkAllegro5Font {
  46. struct nk_user_font nk;
  47. int height;
  48. ALLEGRO_FONT *font;
  49. };
  50. static struct nk_allegro5 {
  51. ALLEGRO_DISPLAY *dsp;
  52. unsigned int width;
  53. unsigned int height;
  54. int is_touch_down;
  55. int touch_down_id;
  56. struct nk_context ctx;
  57. struct nk_buffer cmds;
  58. } allegro5;
  59. NK_API struct nk_image* nk_create_image(const char* file_name)
  60. {
  61. if (!al_init_image_addon()) {
  62. fprintf(stdout, "Unable to initialize required allegro5 image addon\n");
  63. exit(1);
  64. }
  65. ALLEGRO_BITMAP* bitmap = al_load_bitmap(file_name);
  66. if (bitmap == NULL) {
  67. fprintf(stdout, "Unable to load image file: %s\n", file_name);
  68. return NULL;
  69. }
  70. struct nk_image *image = (struct nk_image*)calloc(1, sizeof(struct nk_image));
  71. image->handle.ptr = bitmap;
  72. image->w = al_get_bitmap_width(bitmap);
  73. image->h = al_get_bitmap_height(bitmap);
  74. return image;
  75. }
  76. NK_API void nk_allegro5_del_image(struct nk_image* image)
  77. {
  78. if(!image) return;
  79. al_destroy_bitmap(image->handle.ptr);
  80. free(image);
  81. }
  82. /* Flags are identical to al_load_font() flags argument */
  83. NK_API NkAllegro5Font*
  84. nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags)
  85. {
  86. if (!al_init_image_addon()) {
  87. fprintf(stdout, "Unable to initialize required allegro5 image addon\n");
  88. exit(1);
  89. }
  90. if (!al_init_font_addon()) {
  91. fprintf(stdout, "Unable to initialize required allegro5 font addon\n");
  92. exit(1);
  93. }
  94. if (!al_init_ttf_addon()) {
  95. fprintf(stdout, "Unable to initialize required allegro5 TTF font addon\n");
  96. exit(1);
  97. }
  98. NkAllegro5Font *font = (NkAllegro5Font*)calloc(1, sizeof(NkAllegro5Font));
  99. font->font = al_load_font(file_name, font_size, flags);
  100. if (font->font == NULL) {
  101. fprintf(stdout, "Unable to load font file: %s\n", file_name);
  102. return NULL;
  103. }
  104. font->height = al_get_font_line_height(font->font);
  105. return font;
  106. }
  107. static float
  108. nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)
  109. {
  110. NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;
  111. if (!font || !text) {
  112. return 0;
  113. }
  114. /* We must copy into a new buffer with exact length null-terminated
  115. as nuklear uses variable size buffers and al_get_text_width doesn't
  116. accept a length, it infers length from null-termination
  117. (which is unsafe API design by allegro devs!) */
  118. char strcpy[len+1];
  119. strncpy((char*)&strcpy, text, len);
  120. strcpy[len] = '\0';
  121. return al_get_text_width(font->font, strcpy);
  122. }
  123. NK_API void
  124. nk_allegro5_font_set_font(NkAllegro5Font *allegro5font)
  125. {
  126. struct nk_user_font *font = &allegro5font->nk;
  127. font->userdata = nk_handle_ptr(allegro5font);
  128. font->height = (float)allegro5font->height;
  129. font->width = nk_allegro5_font_get_text_width;
  130. nk_style_set_font(&allegro5.ctx, font);
  131. }
  132. NK_API void
  133. nk_allegro5_font_del(NkAllegro5Font *font)
  134. {
  135. if(!font) return;
  136. al_destroy_font(font->font);
  137. free(font);
  138. }
  139. static ALLEGRO_COLOR
  140. nk_color_to_allegro_color(struct nk_color color)
  141. {
  142. return al_map_rgba((unsigned char)color.r, (unsigned char)color.g,
  143. (unsigned char)color.b, (unsigned char)color.a);
  144. }
  145. NK_API void
  146. nk_allegro5_render()
  147. {
  148. const struct nk_command *cmd;
  149. al_set_target_backbuffer(allegro5.dsp);
  150. nk_foreach(cmd, &allegro5.ctx)
  151. {
  152. ALLEGRO_COLOR color;
  153. switch (cmd->type) {
  154. case NK_COMMAND_NOP: break;
  155. case NK_COMMAND_SCISSOR: {
  156. const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
  157. al_set_clipping_rectangle((int)s->x, (int)s->y, (int)s->w, (int)s->h);
  158. } break;
  159. case NK_COMMAND_LINE: {
  160. const struct nk_command_line *l = (const struct nk_command_line *)cmd;
  161. color = nk_color_to_allegro_color(l->color);
  162. al_draw_line((float)l->begin.x, (float)l->begin.y, (float)l->end.x,
  163. (float)l->end.y, color, (float)l->line_thickness);
  164. } break;
  165. case NK_COMMAND_RECT: {
  166. const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
  167. color = nk_color_to_allegro_color(r->color);
  168. al_draw_rounded_rectangle((float)r->x, (float)r->y, (float)(r->x + r->w),
  169. (float)(r->y + r->h), (float)r->rounding, (float)r->rounding, color,
  170. (float)r->line_thickness);
  171. } break;
  172. case NK_COMMAND_RECT_FILLED: {
  173. const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
  174. color = nk_color_to_allegro_color(r->color);
  175. al_draw_filled_rounded_rectangle((float)r->x, (float)r->y,
  176. (float)(r->x + r->w), (float)(r->y + r->h), (float)r->rounding,
  177. (float)r->rounding, color);
  178. } break;
  179. case NK_COMMAND_CIRCLE: {
  180. const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
  181. color = nk_color_to_allegro_color(c->color);
  182. float xr, yr;
  183. xr = (float)c->w/2;
  184. yr = (float)c->h/2;
  185. al_draw_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
  186. xr, yr, color, (float)c->line_thickness);
  187. } break;
  188. case NK_COMMAND_CIRCLE_FILLED: {
  189. const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
  190. color = nk_color_to_allegro_color(c->color);
  191. float xr, yr;
  192. xr = (float)c->w/2;
  193. yr = (float)c->h/2;
  194. al_draw_filled_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
  195. xr, yr, color);
  196. } break;
  197. case NK_COMMAND_TRIANGLE: {
  198. const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
  199. color = nk_color_to_allegro_color(t->color);
  200. al_draw_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, (float)t->b.y,
  201. (float)t->c.x, (float)t->c.y, color, (float)t->line_thickness);
  202. } break;
  203. case NK_COMMAND_TRIANGLE_FILLED: {
  204. const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
  205. color = nk_color_to_allegro_color(t->color);
  206. al_draw_filled_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x,
  207. (float)t->b.y, (float)t->c.x, (float)t->c.y, color);
  208. } break;
  209. case NK_COMMAND_POLYGON: {
  210. const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
  211. color = nk_color_to_allegro_color(p->color);
  212. int i;
  213. float vertices[p->point_count * 2];
  214. for (i = 0; i < p->point_count; i++) {
  215. vertices[i*2] = p->points[i].x;
  216. vertices[(i*2) + 1] = p->points[i].y;
  217. }
  218. al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
  219. (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED,
  220. color, (float)p->line_thickness, 0.0);
  221. } break;
  222. case NK_COMMAND_POLYGON_FILLED: {
  223. const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
  224. color = nk_color_to_allegro_color(p->color);
  225. int i;
  226. float vertices[p->point_count * 2];
  227. for (i = 0; i < p->point_count; i++) {
  228. vertices[i*2] = p->points[i].x;
  229. vertices[(i*2) + 1] = p->points[i].y;
  230. }
  231. al_draw_filled_polygon((const float*)&vertices, (int)p->point_count, color);
  232. } break;
  233. case NK_COMMAND_POLYLINE: {
  234. const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
  235. color = nk_color_to_allegro_color(p->color);
  236. int i;
  237. float vertices[p->point_count * 2];
  238. for (i = 0; i < p->point_count; i++) {
  239. vertices[i*2] = p->points[i].x;
  240. vertices[(i*2) + 1] = p->points[i].y;
  241. }
  242. al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
  243. (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND,
  244. color, (float)p->line_thickness, 0.0);
  245. } break;
  246. case NK_COMMAND_TEXT: {
  247. const struct nk_command_text *t = (const struct nk_command_text*)cmd;
  248. color = nk_color_to_allegro_color(t->foreground);
  249. NkAllegro5Font *font = (NkAllegro5Font*)t->font->userdata.ptr;
  250. al_draw_text(font->font,
  251. color, (float)t->x, (float)t->y, 0,
  252. (const char*)t->string);
  253. } break;
  254. case NK_COMMAND_CURVE: {
  255. const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
  256. color = nk_color_to_allegro_color(q->color);
  257. float points[8];
  258. points[0] = (float)q->begin.x;
  259. points[1] = (float)q->begin.y;
  260. points[2] = (float)q->ctrl[0].x;
  261. points[3] = (float)q->ctrl[0].y;
  262. points[4] = (float)q->ctrl[1].x;
  263. points[5] = (float)q->ctrl[1].y;
  264. points[6] = (float)q->end.x;
  265. points[7] = (float)q->end.y;
  266. al_draw_spline(points, color, (float)q->line_thickness);
  267. } break;
  268. case NK_COMMAND_ARC: {
  269. const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;
  270. color = nk_color_to_allegro_color(a->color);
  271. al_draw_arc((float)a->cx, (float)a->cy, (float)a->r, a->a[0],
  272. a->a[1], color, (float)a->line_thickness);
  273. } break;
  274. case NK_COMMAND_IMAGE: {
  275. const struct nk_command_image *i = (const struct nk_command_image *)cmd;
  276. al_draw_bitmap_region(i->img.handle.ptr, 0, 0, i->w, i->h, i->x, i->y, 0);
  277. } break;
  278. case NK_COMMAND_RECT_MULTI_COLOR:
  279. case NK_COMMAND_ARC_FILLED:
  280. default: break;
  281. }
  282. }
  283. nk_clear(&allegro5.ctx);
  284. }
  285. NK_API void
  286. nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
  287. {
  288. struct nk_context *ctx = &allegro5.ctx;
  289. switch (ev->type) {
  290. case ALLEGRO_EVENT_DISPLAY_RESIZE: {
  291. allegro5.width = (unsigned int)ev->display.width;
  292. allegro5.height = (unsigned int)ev->display.height;
  293. al_acknowledge_resize(ev->display.source);
  294. } break;
  295. case ALLEGRO_EVENT_MOUSE_AXES: {
  296. nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);
  297. if (ev->mouse.dz != 0) {
  298. nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision()));
  299. }
  300. } break;
  301. case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
  302. case ALLEGRO_EVENT_MOUSE_BUTTON_UP: {
  303. int button = NK_BUTTON_LEFT;
  304. if (ev->mouse.button == 2) {
  305. button = NK_BUTTON_RIGHT;
  306. }
  307. else if (ev->mouse.button == 3) {
  308. button = NK_BUTTON_MIDDLE;
  309. }
  310. nk_input_button(ctx, button, ev->mouse.x, ev->mouse.y, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
  311. } break;
  312. /* This essentially converts touch events to mouse events */
  313. case ALLEGRO_EVENT_TOUCH_BEGIN:
  314. case ALLEGRO_EVENT_TOUCH_END: {
  315. /* We only acknowledge one touch at a time. Otherwise, each touch
  316. would be manipulating multiple nuklear elements, as if there
  317. were multiple mouse cursors */
  318. if (allegro5.is_touch_down && allegro5.touch_down_id != ev->touch.id) {
  319. return;
  320. }
  321. if (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN) {
  322. allegro5.is_touch_down = 1;
  323. allegro5.touch_down_id = ev->touch.id;
  324. /* FIXME: This is a hack to properly simulate
  325. touches as a mouse with nuklear. If you instantly jump
  326. from one place to another without an nk_input_end(), it
  327. confuses the nuklear state. nuklear expects smooth mouse
  328. movements, which is unlike a touch screen */
  329. nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
  330. nk_input_end(ctx);
  331. nk_input_begin(ctx);
  332. }
  333. else {
  334. allegro5.is_touch_down = 0;
  335. allegro5.touch_down_id = -1;
  336. }
  337. nk_input_button(ctx, NK_BUTTON_LEFT, (int)ev->touch.x, (int)ev->touch.y, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
  338. } break;
  339. case ALLEGRO_EVENT_TOUCH_MOVE: {
  340. /* Only acknowledge movements of a single touch, we are
  341. simulating a mouse cursor */
  342. if (!allegro5.is_touch_down || allegro5.touch_down_id != ev->touch.id) {
  343. return;
  344. }
  345. nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
  346. } break;
  347. case ALLEGRO_EVENT_KEY_DOWN:
  348. case ALLEGRO_EVENT_KEY_UP: {
  349. int kc = ev->keyboard.keycode;
  350. int down = ev->type == ALLEGRO_EVENT_KEY_DOWN;
  351. if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down);
  352. else if (kc == ALLEGRO_KEY_DELETE) nk_input_key(ctx, NK_KEY_DEL, down);
  353. else if (kc == ALLEGRO_KEY_ENTER) nk_input_key(ctx, NK_KEY_ENTER, down);
  354. else if (kc == ALLEGRO_KEY_TAB) nk_input_key(ctx, NK_KEY_TAB, down);
  355. else if (kc == ALLEGRO_KEY_LEFT) nk_input_key(ctx, NK_KEY_LEFT, down);
  356. else if (kc == ALLEGRO_KEY_RIGHT) nk_input_key(ctx, NK_KEY_RIGHT, down);
  357. else if (kc == ALLEGRO_KEY_UP) nk_input_key(ctx, NK_KEY_UP, down);
  358. else if (kc == ALLEGRO_KEY_DOWN) nk_input_key(ctx, NK_KEY_DOWN, down);
  359. else if (kc == ALLEGRO_KEY_BACKSPACE) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
  360. else if (kc == ALLEGRO_KEY_ESCAPE) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);
  361. else if (kc == ALLEGRO_KEY_PGUP) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
  362. else if (kc == ALLEGRO_KEY_PGDN) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
  363. else if (kc == ALLEGRO_KEY_HOME) {
  364. nk_input_key(ctx, NK_KEY_TEXT_START, down);
  365. nk_input_key(ctx, NK_KEY_SCROLL_START, down);
  366. } else if (kc == ALLEGRO_KEY_END) {
  367. nk_input_key(ctx, NK_KEY_TEXT_END, down);
  368. nk_input_key(ctx, NK_KEY_SCROLL_END, down);
  369. }
  370. } break;
  371. case ALLEGRO_EVENT_KEY_CHAR: {
  372. int kc = ev->keyboard.keycode;
  373. int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ||
  374. (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND);
  375. if (kc == ALLEGRO_KEY_C && control_mask) {
  376. nk_input_key(ctx, NK_KEY_COPY, 1);
  377. } else if (kc == ALLEGRO_KEY_V && control_mask) {
  378. nk_input_key(ctx, NK_KEY_PASTE, 1);
  379. } else if (kc == ALLEGRO_KEY_X && control_mask) {
  380. nk_input_key(ctx, NK_KEY_CUT, 1);
  381. } else if (kc == ALLEGRO_KEY_Z && control_mask) {
  382. nk_input_key(ctx, NK_KEY_TEXT_UNDO, 1);
  383. } else if (kc == ALLEGRO_KEY_R && control_mask) {
  384. nk_input_key(ctx, NK_KEY_TEXT_REDO, 1);
  385. } else if (kc == ALLEGRO_KEY_A && control_mask) {
  386. nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1);
  387. } else {
  388. if (kc != ALLEGRO_KEY_BACKSPACE &&
  389. kc != ALLEGRO_KEY_LEFT &&
  390. kc != ALLEGRO_KEY_RIGHT &&
  391. kc != ALLEGRO_KEY_UP &&
  392. kc != ALLEGRO_KEY_DOWN &&
  393. kc != ALLEGRO_KEY_HOME &&
  394. kc != ALLEGRO_KEY_DELETE &&
  395. kc != ALLEGRO_KEY_ENTER &&
  396. kc != ALLEGRO_KEY_END &&
  397. kc != ALLEGRO_KEY_ESCAPE &&
  398. kc != ALLEGRO_KEY_PGDN &&
  399. kc != ALLEGRO_KEY_PGUP) {
  400. nk_input_unicode(ctx, ev->keyboard.unichar);
  401. }
  402. }
  403. } break;
  404. default: break;
  405. }
  406. }
  407. NK_INTERN void
  408. nk_allegro5_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
  409. {
  410. char *text = al_get_clipboard_text(allegro5.dsp);
  411. if (text) nk_textedit_paste(edit, text, nk_strlen(text));
  412. (void)usr;
  413. al_free(text);
  414. }
  415. NK_INTERN void
  416. nk_allegro5_clipboard_copy(nk_handle usr, const char *text, int len)
  417. {
  418. char *str = 0;
  419. (void)usr;
  420. if (!len) return;
  421. str = (char*)malloc((size_t)len+1);
  422. if (!str) return;
  423. memcpy(str, text, (size_t)len);
  424. str[len] = '\0';
  425. al_set_clipboard_text(allegro5.dsp, str);
  426. free(str);
  427. }
  428. NK_API struct nk_context*
  429. nk_allegro5_init(NkAllegro5Font *allegro5font, ALLEGRO_DISPLAY *dsp,
  430. unsigned int width, unsigned int height)
  431. {
  432. if (!al_init_primitives_addon()) {
  433. fprintf(stdout, "Unable to initialize required allegro5 primitives addon\n");
  434. exit(1);
  435. }
  436. struct nk_user_font *font = &allegro5font->nk;
  437. font->userdata = nk_handle_ptr(allegro5font);
  438. font->height = (float)allegro5font->height;
  439. font->width = nk_allegro5_font_get_text_width;
  440. allegro5.dsp = dsp;
  441. allegro5.width = width;
  442. allegro5.height = height;
  443. allegro5.is_touch_down = 0;
  444. allegro5.touch_down_id = -1;
  445. nk_init_default(&allegro5.ctx, font);
  446. allegro5.ctx.clip.copy = nk_allegro5_clipboard_copy;
  447. allegro5.ctx.clip.paste = nk_allegro5_clipboard_paste;
  448. allegro5.ctx.clip.userdata = nk_handle_ptr(0);
  449. return &allegro5.ctx;
  450. }
  451. NK_API
  452. void nk_allegro5_shutdown(void)
  453. {
  454. nk_free(&allegro5.ctx);
  455. memset(&allegro5, 0, sizeof(allegro5));
  456. }
  457. #endif /* NK_ALLEGRO5_IMPLEMENTATION */