Browse Source

Added initial work for allegro5 backend

seibelj 8 years ago
parent
commit
e2c48555d4
3 changed files with 621 additions and 0 deletions
  1. 24 0
      demo/allegro5/Makefile
  2. 178 0
      demo/allegro5/main.c
  3. 419 0
      demo/allegro5/nuklear_allegro5.h

+ 24 - 0
demo/allegro5/Makefile

@@ -0,0 +1,24 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+# DEBUG
+#CFLAGS = -std=c99 -pedantic -O0 -g
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+# TODO: Handle Windows build
+#ifeq ($(OS),Windows_NT)
+#BIN := $(BIN).exe
+#LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+#else
+LIBS = -lallegro -lallegro_main -lallegro_image -lallegro_font \
+	-lallegro_ttf -lallegro_primitives -lm
+#endif
+
+$(BIN):
+	@mkdir -p bin
+	rm -f bin/$(BIN) $(OBJS)
+	$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)

+ 178 - 0
demo/allegro5/main.c

@@ -0,0 +1,178 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <allegro5/allegro.h>
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_ALLEGRO5_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_allegro5.h"
+
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+#include "../overview.c"
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+static void error_callback(int e, const char *d)
+{printf("Error %d: %s\n", e, d);}
+
+int main(void)
+{
+    /* Platform */
+    ALLEGRO_DISPLAY *display = NULL;
+    ALLEGRO_EVENT_QUEUE *event_queue = NULL;
+
+    if (!al_init()) {
+        fprintf(stdout, "failed to initialize allegro5!\n");
+        exit(1);
+    }
+
+    al_install_mouse();
+    al_install_keyboard();
+
+    al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_RESIZABLE|ALLEGRO_OPENGL);
+    al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
+    al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
+    display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
+    if (!display) {
+        fprintf(stdout, "failed to create display!\n");
+        exit(1);
+    }
+
+    event_queue = al_create_event_queue();
+    if (!event_queue) {
+        fprintf(stdout, "failed to create event_queue!\n");
+        al_destroy_display(display);
+        exit(1);
+    }
+
+    al_register_event_source(event_queue, al_get_display_event_source(display));
+    al_register_event_source(event_queue, al_get_mouse_event_source());
+    al_register_event_source(event_queue, al_get_keyboard_event_source());
+
+    NkAllegro5Font *font;
+    font = nk_allegro5_font_create_from_file("../../extra_font/DroidSans.ttf", 12, 0);
+    struct nk_context *ctx;
+    struct nk_color background;
+
+    ctx = nk_allegro5_init(font, display, WINDOW_WIDTH, WINDOW_HEIGHT);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle);*/
+
+    /* style.c */
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+
+    background = nk_rgb(28,48,62);
+
+    while(1)
+    {
+        ALLEGRO_EVENT ev;
+        ALLEGRO_TIMEOUT timeout;
+        al_init_timeout(&timeout, 0.06);
+
+        bool get_event = al_wait_for_event_until(event_queue, &ev, &timeout);
+
+        if (get_event && ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
+            break;
+        }
+
+        if (get_event) {
+            nk_input_begin(ctx);
+            while (get_event) {
+                nk_allegro5_handle_event(&ev);
+                get_event = al_get_next_event(event_queue, &ev);
+            }
+            nk_input_end(ctx);
+        }
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        /*calculator(ctx);*/
+        overview(ctx);
+        /*node_editor(ctx);*/
+        /* ----------------------------------------- */
+
+        /* Draw */
+        //al_reset_clipping_rectangle();
+        al_clear_to_color(al_map_rgb(19, 43, 81));
+        /* IMPORTANT: `nk_allegro5_render` changes the target backbuffer
+        to the display set at initialization and does not restore it.
+        Change it if you want to draw somewhere else. */
+        nk_allegro5_render();
+        al_flip_display();
+    }
+
+    nk_allegro5_font_del(font);
+    nk_allegro5_shutdown();
+    al_destroy_display(display);
+    al_destroy_event_queue(event_queue);
+    return 0;
+}
+

+ 419 - 0
demo/allegro5/nuklear_allegro5.h

@@ -0,0 +1,419 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_ALLEGRO5_H_
+#define NK_ALLEGRO5_H_
+
+#include <allegro5/allegro.h>
+#include <allegro5/allegro_image.h>
+#include <allegro5/allegro_primitives.h>
+#include <allegro5/allegro_font.h>
+#include <allegro5/allegro_ttf.h>
+
+typedef struct NkAllegro5Font NkAllegro5Font;
+NK_API struct nk_context*   nk_allegro5_init(NkAllegro5Font *font, ALLEGRO_DISPLAY *dsp, unsigned int width, unsigned int height);
+NK_API void                 nk_allegro5_handle_event(ALLEGRO_EVENT *ev);
+NK_API void                 nk_allegro5_shutdown(void);
+NK_API void                 nk_allegro5_render(void);
+
+// Fonts. We wrap normal allegro fonts in some nuklear book keeping
+NK_API NkAllegro5Font*      nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags);
+NK_API void                 nk_allegro5_font_del(NkAllegro5Font *font);
+NK_API void                 nk_allegro5_font_set_font(NkAllegro5Font *font);
+
+//NK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
+//NK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_ALLEGRO5_IMPLEMENTATION
+
+#ifndef NK_ALLEGRO5_TEXT_MAX
+#define NK_ALLEGRO5_TEXT_MAX 256
+#endif
+
+
+struct NkAllegro5Font {
+    struct nk_user_font nk;
+    int height;
+    ALLEGRO_FONT *font;
+};
+
+static struct nk_allegro5 {
+    ALLEGRO_DISPLAY *dsp;
+    unsigned int width;
+    unsigned int height;
+    struct nk_context ctx;
+    struct nk_buffer cmds;
+} allegro5;
+
+
+// Flags are identical to al_load_font() flags argument
+NK_API NkAllegro5Font*
+nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags)
+{
+    if (!al_init_image_addon()) {
+        fprintf(stdout, "Unable to initialize required allegro5 image addon\n");
+        exit(1);
+    }
+    if (!al_init_font_addon()) {
+        fprintf(stdout, "Unable to initialize required allegro5 font addon\n");
+        exit(1);
+    }
+    if (!al_init_ttf_addon()) {
+        fprintf(stdout, "Unable to initialize required allegro5 TTF font addon\n");
+        exit(1);
+    }
+    NkAllegro5Font *font = (NkAllegro5Font*)calloc(1, sizeof(NkAllegro5Font));
+
+    font->font = al_load_font(file_name, font_size, flags);
+    if (font->font == NULL) {
+        fprintf(stdout, "Unable to load font file: %s\n", file_name);
+        return NULL;
+    }
+    font->height = al_get_font_line_height(font->font);
+    return font;
+}
+
+static float
+nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+    NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;
+
+    if (!font || !text) {
+        return 0;
+    }
+
+    return (float)al_get_text_width(font->font, text);
+}
+
+NK_API void
+nk_allegro5_font_set_font(NkAllegro5Font *allegro5font)
+{
+    struct nk_user_font *font = &allegro5font->nk;
+    font->userdata = nk_handle_ptr(allegro5font);
+    font->height = (float)allegro5font->height;
+    font->width = nk_allegro5_font_get_text_width;
+    nk_style_set_font(&allegro5.ctx, font);
+}
+
+NK_API void
+nk_allegro5_font_del(NkAllegro5Font *font)
+{
+    if(!font) return;
+    al_destroy_font(font->font);
+    free(font);
+}
+
+static ALLEGRO_COLOR
+nk_color_to_allegro_color(struct nk_color color)
+{
+    return al_map_rgba((unsigned char)color.r, (unsigned char)color.g,
+                (unsigned char)color.b, (unsigned char)color.a);
+}
+
+NK_API void
+nk_allegro5_render()
+{
+    const struct nk_command *cmd;
+
+    al_set_target_backbuffer(allegro5.dsp);
+
+    nk_foreach(cmd, &allegro5.ctx)
+    {
+        ALLEGRO_COLOR color;
+        switch (cmd->type) {
+        case NK_COMMAND_NOP: break;
+        case NK_COMMAND_SCISSOR: {
+            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+            al_set_clipping_rectangle((int)s->x, (int)s->y, (int)s->w, (int)s->h);
+        } break;
+        case NK_COMMAND_LINE: {
+            const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+            color = nk_color_to_allegro_color(l->color);
+            al_draw_line((float)l->begin.x, (float)l->begin.y, (float)l->end.x,
+                (float)l->end.y, color, (float)l->line_thickness);
+        } break;
+        case NK_COMMAND_RECT: {
+            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+            color = nk_color_to_allegro_color(r->color);
+            al_draw_rounded_rectangle((float)r->x, (float)r->y, (float)(r->x + r->w),
+                (float)(r->y + r->h), (float)r->rounding, (float)r->rounding, color,
+                (float)r->line_thickness);
+        } break;
+        case NK_COMMAND_RECT_FILLED: {
+            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+            color = nk_color_to_allegro_color(r->color);
+            al_draw_filled_rounded_rectangle((float)r->x, (float)r->y,
+                (float)(r->x + r->w), (float)(r->y + r->h), (float)r->rounding,
+                (float)r->rounding, color);
+        } break;
+        case NK_COMMAND_CIRCLE: {
+            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+            color = nk_color_to_allegro_color(c->color);
+            float xr, yr;
+            xr = (float)c->w/2;
+            yr = (float)c->h/2;
+            al_draw_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
+                xr, yr, color, (float)c->line_thickness);
+        } break;
+        case NK_COMMAND_CIRCLE_FILLED: {
+            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+            color = nk_color_to_allegro_color(c->color);
+            float xr, yr;
+            xr = (float)c->w/2;
+            yr = (float)c->h/2;
+            al_draw_filled_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
+                xr, yr, color);
+        } break;
+        case NK_COMMAND_TRIANGLE: {
+            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+            color = nk_color_to_allegro_color(t->color);
+            al_draw_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, (float)t->b.y,
+                (float)t->c.x, (float)t->c.y, color, (float)t->line_thickness);
+        } break;
+        case NK_COMMAND_TRIANGLE_FILLED: {
+            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+            color = nk_color_to_allegro_color(t->color);
+            al_draw_filled_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x,
+                (float)t->b.y, (float)t->c.x, (float)t->c.y, color);
+        } break;
+        case NK_COMMAND_POLYGON: {
+            const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
+            color = nk_color_to_allegro_color(p->color);
+            int i;
+            float vertices[p->point_count * 2];
+            for (i = 0; i < p->point_count; i++) {
+                vertices[i*2] = p->points[i].x;
+                vertices[(i*2) + 1] = p->points[i].y;
+            }
+            al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
+                (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED,
+                color, (float)p->line_thickness, 0.0);
+        } break;
+        case NK_COMMAND_POLYGON_FILLED: {
+            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+            color = nk_color_to_allegro_color(p->color);
+            int i;
+            float vertices[p->point_count * 2];
+            for (i = 0; i < p->point_count; i++) {
+                vertices[i*2] = p->points[i].x;
+                vertices[(i*2) + 1] = p->points[i].y;
+            }
+            al_draw_filled_polygon((const float*)&vertices, (int)p->point_count, color);
+        } break;
+        case NK_COMMAND_POLYLINE: {
+            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+            color = nk_color_to_allegro_color(p->color);
+            int i;
+            float vertices[p->point_count * 2];
+            for (i = 0; i < p->point_count; i++) {
+                vertices[i*2] = p->points[i].x;
+                vertices[(i*2) + 1] = p->points[i].y;
+            }
+            al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
+                (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND,
+                color, (float)p->line_thickness, 0.0);
+        } break;
+        case NK_COMMAND_TEXT: {
+            const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+            color = nk_color_to_allegro_color(t->foreground);
+            NkAllegro5Font *font = (NkAllegro5Font*)t->font->userdata.ptr;
+            al_draw_text(font->font,
+                color, (float)t->x, (float)t->y, 0,
+                (const char*)t->string);
+        } break;
+        case NK_COMMAND_CURVE: {
+            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+            color = nk_color_to_allegro_color(q->color);
+            float points[8];
+            points[0] = (float)q->begin.x;
+            points[1] = (float)q->begin.y;
+            points[2] = (float)q->ctrl[0].x;
+            points[3] = (float)q->ctrl[0].y;
+            points[4] = (float)q->ctrl[1].x;
+            points[5] = (float)q->ctrl[1].y;
+            points[6] = (float)q->end.x;
+            points[7] = (float)q->end.y;
+            al_draw_spline(points, color, (float)q->line_thickness);
+        } break;
+        case NK_COMMAND_ARC: {
+            const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;
+            color = nk_color_to_allegro_color(a->color);
+            al_draw_arc((float)a->cx, (float)a->cy, (float)a->r, a->a[0],
+                a->a[1], color, (float)a->line_thickness);
+        } break;
+        case NK_COMMAND_RECT_MULTI_COLOR:
+        case NK_COMMAND_IMAGE:
+        case NK_COMMAND_ARC_FILLED:
+        default: break;
+        }
+    }
+    nk_clear(&allegro5.ctx);
+}
+
+NK_API void
+nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
+{
+    struct nk_context *ctx = &allegro5.ctx;
+    //printf("nk_allegro5_handle_event: %d\n", ev->type);
+    switch (ev->type) {
+        case ALLEGRO_EVENT_MOUSE_AXES: {
+            nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);
+        } break;
+        case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
+        case ALLEGRO_EVENT_MOUSE_BUTTON_UP: {
+            if (ev->mouse.display != allegro5.dsp) {
+                return;
+            }
+            int button = NK_BUTTON_LEFT;
+            if (ev->mouse.button == 2) {
+                button = NK_BUTTON_RIGHT;
+            }
+            else if (ev->mouse.button == 3) {
+                button = NK_BUTTON_MIDDLE;
+            }
+            nk_input_button(ctx, button, ev->mouse.x, ev->mouse.y, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
+        } break;
+        case ALLEGRO_EVENT_KEY_DOWN:
+        case ALLEGRO_EVENT_KEY_UP: {
+            if (ev->keyboard.display != allegro5.dsp) {
+                return;
+            }
+            int kc = ev->keyboard.keycode;
+            int down = ev->type == ALLEGRO_EVENT_KEY_DOWN;
+            if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down);
+            else if (kc == ALLEGRO_KEY_DELETE)    nk_input_key(ctx, NK_KEY_DEL, down);
+            else if (kc == ALLEGRO_KEY_ENTER)    nk_input_key(ctx, NK_KEY_ENTER, down);
+            else if (kc == ALLEGRO_KEY_TAB)       nk_input_key(ctx, NK_KEY_TAB, down);
+            else if (kc == ALLEGRO_KEY_LEFT)      nk_input_key(ctx, NK_KEY_LEFT, down);
+            else if (kc == ALLEGRO_KEY_RIGHT)     nk_input_key(ctx, NK_KEY_RIGHT, down);
+            else if (kc == ALLEGRO_KEY_UP)        nk_input_key(ctx, NK_KEY_UP, down);
+            else if (kc == ALLEGRO_KEY_DOWN)      nk_input_key(ctx, NK_KEY_DOWN, down);
+            else if (kc == ALLEGRO_KEY_BACKSPACE) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+            else if (kc == ALLEGRO_KEY_ESCAPE)    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);
+            else if (kc == ALLEGRO_KEY_PGUP)   nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+            else if (kc == ALLEGRO_KEY_PGDN) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+            else if (kc == ALLEGRO_KEY_HOME) {
+                nk_input_key(ctx, NK_KEY_TEXT_START, down);
+                nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+            } else if (kc == ALLEGRO_KEY_END) {
+                nk_input_key(ctx, NK_KEY_TEXT_END, down);
+                nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+            }
+        } break;
+        case ALLEGRO_EVENT_KEY_CHAR: {
+            
+            int kc = ev->keyboard.keycode;
+            int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ||
+                               (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND);
+            
+            if (kc == ALLEGRO_KEY_C && control_mask) {
+                nk_input_key(ctx, NK_KEY_COPY, 1);
+            } else if (kc == ALLEGRO_KEY_V && control_mask) {
+                nk_input_key(ctx, NK_KEY_PASTE, 1);
+            } else if (kc == ALLEGRO_KEY_X && control_mask) {
+                nk_input_key(ctx, NK_KEY_CUT, 1);
+            } else if (kc == ALLEGRO_KEY_Z && control_mask) {
+                nk_input_key(ctx, NK_KEY_TEXT_UNDO, 1);
+            } else if (kc == ALLEGRO_KEY_R && control_mask) {
+                nk_input_key(ctx, NK_KEY_TEXT_REDO, 1);
+            }
+            else {
+                
+                if (ev->keyboard.keycode != ALLEGRO_KEY_BACKSPACE) {
+                    printf("unicode: %c\n", ev->keyboard.unichar);
+                    nk_input_unicode(ctx, ev->keyboard.unichar);
+                }
+            }
+
+        } break;
+        default: break;
+    }
+}
+
+// NK_API void
+// nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
+// {
+//     (void)win;
+//     if (glfw.text_len < NK_GLFW_TEXT_MAX)
+//         glfw.text[glfw.text_len++] = codepoint;
+// }
+
+// NK_API void
+// nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
+// {
+//     /*(void)win; (void)xoff;
+//     glfw.scroll += (float)yoff;*/
+// }
+
+NK_INTERN void
+nk_allegro5_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    char *text = al_get_clipboard_text(allegro5.dsp);
+    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+    (void)usr;
+    al_free(text);
+}
+
+NK_INTERN void
+nk_allegro5_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+    char *str = 0;
+    (void)usr;
+    if (!len) return;
+    str = (char*)malloc((size_t)len+1);
+    if (!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+    al_set_clipboard_text(allegro5.dsp, str);
+    free(str);
+}
+
+NK_API struct nk_context*
+nk_allegro5_init(NkAllegro5Font *allegro5font, ALLEGRO_DISPLAY *dsp, unsigned int width, unsigned int height)
+{
+    if (!al_init_primitives_addon()) {
+        fprintf(stdout, "Unable to initialize required allegro5 primitives addon\n");
+        exit(1);
+    }
+
+    struct nk_user_font *font = &allegro5font->nk;
+    font->userdata = nk_handle_ptr(allegro5font);
+    font->height = (float)allegro5font->height;
+    font->width = nk_allegro5_font_get_text_width;
+
+    allegro5.dsp = dsp;
+    allegro5.width = width;
+    allegro5.height = height;
+
+    nk_init_default(&allegro5.ctx, font);
+    allegro5.ctx.clip.copy = nk_allegro5_clipboard_copy;
+    allegro5.ctx.clip.paste = nk_allegro5_clipboard_paste;
+    allegro5.ctx.clip.userdata = nk_handle_ptr(0);
+    return &allegro5.ctx;
+}
+
+NK_API
+void nk_allegro5_shutdown(void)
+{
+    nk_free(&allegro5.ctx);
+    memset(&allegro5, 0, sizeof(allegro5));
+}
+
+#endif // NK_ALLEGRO5_IMPLEMENTATION