#define NK_IMPLEMENTATION #include "../../nuklear.h" #include #include struct nk_allegro_device { ALLEGRO_BITMAP *texture; ALLEGRO_VERTEX_DECL *vertex_decl; struct nk_draw_null_texture null; struct nk_buffer cmds; void *vertex_buffer; void *element_buffer; int max_vertex_memory; int max_element_memory; }; struct nk_allegro_vertex { struct nk_vec2 pos; struct nk_vec2 uv; ALLEGRO_COLOR col; }; static struct { ALLEGRO_DISPLAY *win; struct nk_allegro_device dev; struct nk_context ctx; struct nk_font_atlas atlas; } allegro; NK_API void nk_allegro_device_create(int max_vertex_memory, int max_element_memory) { struct nk_allegro_device *dev = &allegro.dev; ALLEGRO_VERTEX_ELEMENT elems[] = { {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(struct nk_allegro_vertex, pos)}, {ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(struct nk_allegro_vertex, uv)}, {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(struct nk_allegro_vertex, col)}, {0,0,0} }; dev->vertex_decl = al_create_vertex_decl(elems, sizeof(struct nk_allegro_vertex)); dev->vertex_buffer = calloc((size_t)max_vertex_memory, 1); dev->element_buffer = calloc((size_t)max_element_memory, 1); dev->max_vertex_memory = max_vertex_memory; dev->max_element_memory = max_element_memory; nk_buffer_init_default(&dev->cmds); } static void nk_allegro_device_upload_atlas(const void *image, int width, int height) { /* create allegro font bitmap */ ALLEGRO_BITMAP *bitmap = 0; struct nk_allegro_device *dev = &allegro.dev; int flags = al_get_new_bitmap_flags(); int fmt = al_get_new_bitmap_format(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE); bitmap = al_create_bitmap(width, height); al_set_new_bitmap_flags(flags); al_set_new_bitmap_format(fmt); assert(bitmap); {/* copy font texture into bitmap */ ALLEGRO_LOCKED_REGION * locked_img; locked_img = al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_WRITEONLY); assert(locked_img); memcpy(locked_img->data, image, sizeof(uint32_t)*(size_t)(width*height)); al_unlock_bitmap(bitmap);} /* convert software texture into hardware texture */ dev->texture = al_clone_bitmap(bitmap); al_destroy_bitmap(bitmap); assert(dev->texture); } NK_API void nk_allegro_render(enum nk_anti_aliasing AA) { int op, src, dst; struct nk_allegro_device *dev = &allegro.dev; struct nk_context *ctx = &allegro.ctx; al_get_blender(&op, &src, &dst); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); { const struct nk_draw_command *cmd; struct nk_buffer vbuf, ebuf; int offset = 0; struct nk_allegro_vertex *vertices = 0; int *indices = 0; /* fill converting configuration */ struct nk_convert_config config; memset(&config, 0, sizeof(config)); config.global_alpha = 1.0f; config.shape_AA = AA; config.line_AA = AA; config.circle_segment_count = 22; config.arc_segment_count = 22; config.curve_segment_count = 22; config.null = dev->null; /* convert from command into hardware format */ nk_buffer_init_fixed(&vbuf, dev->vertex_buffer, (nk_size)dev->max_vertex_memory); nk_buffer_init_fixed(&ebuf, dev->element_buffer, (nk_size)dev->max_element_memory); nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config); { /* allegro does not support 32-bit packed color */ unsigned int i = 0; struct nk_draw_vertex *verts = (struct nk_draw_vertex*)dev->vertex_buffer; vertices = calloc(sizeof(struct nk_allegro_vertex), ctx->draw_list.vertex_count); for (i = 0; i < ctx->draw_list.vertex_count; ++i) { nk_byte *c; vertices[i].pos = verts[i].position; vertices[i].uv = verts[i].uv; c = (nk_byte*)&verts[i].col; vertices[i].col = al_map_rgba(c[0], c[1], c[2], c[3]); } } { /* allegro does not support 16-bit indices: * @OPT: define nk_draw_index as int to fix this issue. */ unsigned int i = 0; nk_draw_index *elements = (nk_draw_index*)dev->element_buffer; indices = calloc(sizeof(int), ctx->draw_list.element_count); for (i = 0; i < ctx->draw_list.element_count; ++i) indices[i] = elements[i]; } /* iterate over and execute each draw command */ nk_draw_foreach(cmd, ctx, &dev->cmds) { ALLEGRO_BITMAP *texture = cmd->texture.ptr; if (!cmd->elem_count) continue; al_set_clipping_rectangle((int)cmd->clip_rect.x, (int)cmd->clip_rect.y, (int)cmd->clip_rect.w, (int)cmd->clip_rect.h); al_draw_indexed_prim(vertices, dev->vertex_decl, texture, &indices[offset], (int)cmd->elem_count, ALLEGRO_PRIM_TRIANGLE_LIST); offset += cmd->elem_count; } free(vertices); free(indices); nk_clear(ctx); } al_set_blender(op, src, dst); al_set_clipping_rectangle(0,0, al_get_display_width(allegro.win), al_get_display_height(allegro.win)); } NK_API void nk_allegro_device_destroy(void) { struct nk_allegro_device *dev = &allegro.dev; free(dev->vertex_buffer); free(dev->element_buffer); nk_buffer_free(&dev->cmds); } NK_API struct nk_context* nk_allegro_init(ALLEGRO_DISPLAY *win, int max_vertex_memory, int max_element_memory) { allegro.win = win; nk_init_default(&allegro.ctx, 0); nk_allegro_device_create(max_vertex_memory, max_element_memory); return &allegro.ctx; } NK_API void nk_allegro_font_stash_begin(struct nk_font_atlas **atlas) { nk_font_atlas_init_default(&allegro.atlas); nk_font_atlas_begin(&allegro.atlas); *atlas = &allegro.atlas; } NK_API void nk_allegro_font_stash_end(void) { const void *image; int w, h; image = nk_font_atlas_bake(&allegro.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); nk_allegro_device_upload_atlas(image, w, h); nk_font_atlas_end(&allegro.atlas, nk_handle_ptr(allegro.dev.texture), &allegro.dev.null); if (allegro.atlas.default_font) nk_style_set_font(&allegro.ctx, &allegro.atlas.default_font->handle); } NK_API void nk_allegro_handle_event(ALLEGRO_EVENT *evt) { struct nk_context *ctx = &allegro.ctx; if ((evt->type == ALLEGRO_EVENT_KEY_UP || evt->type == ALLEGRO_EVENT_KEY_DOWN) && evt->keyboard.display == allegro.win) { /* key handler */ int down = (evt->type == ALLEGRO_EVENT_KEY_UP); int sym = evt->keyboard.keycode; if (sym == ALLEGRO_KEY_RSHIFT || sym == ALLEGRO_KEY_LSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down); else if (sym == ALLEGRO_KEY_DELETE) nk_input_key(ctx, NK_KEY_DEL, down); else if (sym == ALLEGRO_KEY_ENTER) nk_input_key(ctx, NK_KEY_ENTER, down); else if (sym == ALLEGRO_KEY_TAB) nk_input_key(ctx, NK_KEY_TAB, down); else if (sym == ALLEGRO_KEY_BACKSPACE) nk_input_key(ctx, NK_KEY_BACKSPACE, down); else if (sym == ALLEGRO_KEY_LEFT) { if (evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); else nk_input_key(ctx, NK_KEY_LEFT, down); } else if (sym == ALLEGRO_KEY_RIGHT) { if (evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); else nk_input_key(ctx, NK_KEY_RIGHT, down); } else if (sym == ALLEGRO_KEY_HOME) nk_input_key(ctx, NK_KEY_TEXT_START, down); else if (sym == ALLEGRO_KEY_END) nk_input_key(ctx, NK_KEY_TEXT_END, down); else if (sym == ALLEGRO_KEY_C) nk_input_key(ctx, NK_KEY_COPY, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_V) nk_input_key(ctx, NK_KEY_PASTE, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_X) nk_input_key(ctx, NK_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_Z) nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_R) nk_input_key(ctx, NK_KEY_TEXT_REDO, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_X) nk_input_key(ctx, NK_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_B) nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); else if (sym == ALLEGRO_KEY_E) nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); } else if (evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN || evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { /* button handler */ int down = evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; const int x = evt->mouse.x, y = evt->mouse.y; if (evt->mouse.button == 1) nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); if (evt->mouse.button == 2) nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); } else if (evt->type == ALLEGRO_EVENT_MOUSE_AXES) { /* mouse motion */ nk_input_motion(ctx, evt->mouse.x, evt->mouse.y); } else if (evt->type == ALLEGRO_EVENT_KEY_CHAR) { /* text input */ if (evt->keyboard.display == allegro.win) if (evt->keyboard.unichar > 0 && evt->keyboard.unichar < 0x10000) nk_input_unicode(ctx, (nk_rune)evt->keyboard.unichar); } } NK_API void nk_allegro_shutdown(void) { if (allegro.dev.texture) al_destroy_bitmap(allegro.dev.texture); free(allegro.dev.vertex_buffer); free(allegro.dev.element_buffer); }