123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /*
- * Nuklear - 1.32.0 - 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 <string.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 int nk_allegro5_handle_event(ALLEGRO_EVENT *ev);
- NK_API void nk_allegro5_shutdown(void);
- NK_API void nk_allegro5_render(void);
- NK_API struct nk_image* nk_allegro5_create_image(const char* file_name);
- NK_API void nk_allegro5_del_image(struct nk_image* image);
- /* 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);
- /* NOTE : just use NkAllegro5Font instead of nk_user_font,
- since the former just extends the latter*/
- NK_API void nk_allegro5_font_set_font(NkAllegro5Font *font);
- #endif
- /*
- * ==============================================================
- *
- * IMPLEMENTATION
- *
- * ===============================================================
- */
- #ifdef NK_ALLEGRO5_IMPLEMENTATION
- #include <stdio.h>
- #ifndef NK_ALLEGRO5_TEXT_MAX
- #define NK_ALLEGRO5_TEXT_MAX 256
- #endif
- struct NkAllegro5Font {
- struct nk_user_font nk;
- ALLEGRO_FONT *font;
- };
- static struct nk_allegro5 {
- ALLEGRO_DISPLAY *dsp;
- unsigned int width;
- unsigned int height;
- int is_touch_down;
- int touch_down_id;
- struct nk_context ctx;
- struct nk_buffer cmds;
- float delta_time_seconds_last;
- } allegro5;
- NK_API struct nk_image* nk_allegro5_create_image(const char* file_name)
- {
- ALLEGRO_BITMAP *bitmap;
- struct nk_image *image;
- if (!al_init_image_addon()) {
- fprintf(stdout, "Unable to initialize required allegro5 image addon\n");
- exit(1);
- }
- bitmap = al_load_bitmap(file_name);
- if (bitmap == NULL) {
- fprintf(stdout, "Unable to load image file: %s\n", file_name);
- return NULL;
- }
- image = (struct nk_image*)calloc(1, sizeof(struct nk_image));
- image->handle.ptr = bitmap;
- image->w = al_get_bitmap_width(bitmap);
- image->h = al_get_bitmap_height(bitmap);
- return image;
- }
- NK_API void nk_allegro5_del_image(struct nk_image* image)
- {
- if(!image) return;
- al_destroy_bitmap(image->handle.ptr);
- free(image);
- }
- static float
- nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)
- {
- float width;
- char *str;
- NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;
- NK_UNUSED(height);
- if (!font || !text) {
- return 0;
- }
- /* We must copy into a new buffer with exact length null-terminated
- as nuklear uses variable size buffers and al_get_text_width doesn't
- accept a length, it infers length from null-termination
- (which is unsafe API design by allegro devs!) */
- str = calloc((size_t)len + 1, 1);
- if(!str) return 0;
- strncpy(str, text, len);
- width = al_get_text_width(font->font, str);
- free(str);
- return width;
- }
- /* 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)
- {
- NkAllegro5Font *font;
- 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);
- }
- 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->nk.userdata = nk_handle_ptr(font);
- font->nk.height = (float)al_get_font_line_height(font->font);
- font->nk.width = nk_allegro5_font_get_text_width;
- return font;
- }
- NK_API void
- nk_allegro5_font_set_font(NkAllegro5Font *allegro5font)
- {
- struct nk_user_font *font = &allegro5font->nk;
- 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;
- /* Update the timer */
- float now = (float)al_get_time();
- allegro5.ctx.delta_time_seconds = now - allegro5.delta_time_seconds_last;
- allegro5.delta_time_seconds_last = now;
- 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: {
- float xr, yr;
- const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
- color = nk_color_to_allegro_color(c->color);
- 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: {
- float xr, yr;
- const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
- color = nk_color_to_allegro_color(c->color);
- 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: {
- int i;
- float *vertices;
- const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
- vertices = calloc(p->point_count * 2, sizeof(float));
- color = nk_color_to_allegro_color(p->color);
- 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(vertices, (2 * sizeof(float)),
- (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED,
- color, (float)p->line_thickness, 0.0);
- free(vertices);
- } break;
- case NK_COMMAND_POLYGON_FILLED: {
- int i, j = 0;
- float *vertices;
- const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
- vertices = calloc(p->point_count * 2, sizeof(float));
- color = nk_color_to_allegro_color(p->color);
- for (i = p->point_count - 1; i >= 0; i--) {
- vertices[j++] = p->points[i].x;
- vertices[j++] = p->points[i].y;
- }
- al_draw_filled_polygon(vertices, (int)p->point_count, color);
- free(vertices);
- } break;
- case NK_COMMAND_POLYLINE: {
- int i;
- float *vertices;
- const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
- vertices = calloc(p->point_count * 2, sizeof(float));
- color = nk_color_to_allegro_color(p->color);
- 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(vertices, (2 * sizeof(float)),
- (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND,
- color, (float)p->line_thickness, 0.0);
- free(vertices);
- } break;
- case NK_COMMAND_TEXT: {
- NkAllegro5Font *font;
- const struct nk_command_text *t = (const struct nk_command_text*)cmd;
- color = nk_color_to_allegro_color(t->foreground);
- 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: {
- float points[8];
- const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
- color = nk_color_to_allegro_color(q->color);
- 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_pieslice((float)a->cx, (float)a->cy, (float)a->r, a->a[0],
- a->a[1], color, (float)a->line_thickness);
- } break;
- case NK_COMMAND_ARC_FILLED: {
- const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled *)cmd;
- color = nk_color_to_allegro_color(a->color);
- al_draw_filled_pieslice((float)a->cx, (float)a->cy, (float)a->r, a->a[0],
- a->a[1], color);
- } break;
- case NK_COMMAND_IMAGE: {
- const struct nk_command_image *i = (const struct nk_command_image *)cmd;
- nk_ushort
- x = i->img.region[0],
- y = i->img.region[1],
- w = i->img.region[2],
- h = i->img.region[3];
- if(w == 0 && h == 0)
- {
- x = i->x; y = i->y; w = i->w; h = i->h;
- }
- al_draw_scaled_bitmap(i->img.handle.ptr,
- x, y, w, h, i->x, i->y, i->w, i->h, 0);
- } break;
- case NK_COMMAND_RECT_MULTI_COLOR:
- default: break;
- }
- }
- nk_clear(&allegro5.ctx);
- }
- NK_API int
- nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
- {
- struct nk_context *ctx = &allegro5.ctx;
- switch (ev->type) {
- case ALLEGRO_EVENT_DISPLAY_RESIZE: {
- allegro5.width = (unsigned int)ev->display.width;
- allegro5.height = (unsigned int)ev->display.height;
- al_acknowledge_resize(ev->display.source);
- return 1;
- } break;
- case ALLEGRO_EVENT_MOUSE_AXES: {
- nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);
- if (ev->mouse.dz != 0) {
- nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision()));
- }
- return 1;
- } break;
- case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
- case ALLEGRO_EVENT_MOUSE_BUTTON_UP: {
- 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);
- return 1;
- } break;
- /* This essentially converts touch events to mouse events */
- case ALLEGRO_EVENT_TOUCH_BEGIN:
- case ALLEGRO_EVENT_TOUCH_END: {
- /* We only acknowledge one touch at a time. Otherwise, each touch
- would be manipulating multiple nuklear elements, as if there
- were multiple mouse cursors */
- if (allegro5.is_touch_down && allegro5.touch_down_id != ev->touch.id) {
- return 0;
- }
- if (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN) {
- allegro5.is_touch_down = 1;
- allegro5.touch_down_id = ev->touch.id;
- /* FIXME: This is a hack to properly simulate
- touches as a mouse with nuklear. If you instantly jump
- from one place to another without an nk_input_end(), it
- confuses the nuklear state. nuklear expects smooth mouse
- movements, which is unlike a touch screen */
- nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
- nk_input_end(ctx);
- nk_input_begin(ctx);
- }
- else {
- allegro5.is_touch_down = 0;
- allegro5.touch_down_id = -1;
- }
- nk_input_button(ctx, NK_BUTTON_LEFT, (int)ev->touch.x, (int)ev->touch.y, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
- return 1;
- } break;
- case ALLEGRO_EVENT_TOUCH_MOVE: {
- /* Only acknowledge movements of a single touch, we are
- simulating a mouse cursor */
- if (!allegro5.is_touch_down || allegro5.touch_down_id != ev->touch.id) {
- return 0;
- }
- nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
- return 1;
- } break;
- case ALLEGRO_EVENT_KEY_DOWN:
- case ALLEGRO_EVENT_KEY_UP: {
- 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 || kc == ALLEGRO_KEY_PAD_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);
- }
- return 1;
- } 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 (kc == ALLEGRO_KEY_A && control_mask) {
- nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1);
- } else {
- if (kc != ALLEGRO_KEY_BACKSPACE &&
- kc != ALLEGRO_KEY_LEFT &&
- kc != ALLEGRO_KEY_RIGHT &&
- kc != ALLEGRO_KEY_UP &&
- kc != ALLEGRO_KEY_DOWN &&
- kc != ALLEGRO_KEY_HOME &&
- kc != ALLEGRO_KEY_DELETE &&
- kc != ALLEGRO_KEY_ENTER &&
- kc != ALLEGRO_KEY_END &&
- kc != ALLEGRO_KEY_ESCAPE &&
- kc != ALLEGRO_KEY_PGDN &&
- kc != ALLEGRO_KEY_PGUP) {
- nk_input_unicode(ctx, ev->keyboard.unichar);
- }
- }
- return 1;
- } break;
- default: return 0; break;
- }
- }
- 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 = calloc((size_t)len + 1, 1);
- if (!str) return;
- strncpy(str, text, len);
- 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)
- {
- struct nk_user_font *font;
- if (!al_init_primitives_addon()) {
- fprintf(stdout, "Unable to initialize required allegro5 primitives addon\n");
- exit(1);
- }
- font = &allegro5font->nk;
- allegro5.dsp = dsp;
- allegro5.width = width;
- allegro5.height = height;
- allegro5.is_touch_down = 0;
- allegro5.touch_down_id = -1;
- allegro5.delta_time_seconds_last = (float)al_get_time();
- 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 */
|