From 7665c3052f22d2beef6a9e69529d651554cb6531 Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Wed, 22 Jun 2016 00:53:46 -0700 Subject: [PATCH] nuklear improvements --- src/renderer/backend.h | 4 +- src/renderer/gl_backend.c | 4 +- src/ui/microprofile.cc | 4 +- src/ui/nuklear.c | 231 ++++++++++++-------------------------- src/ui/nuklear.h | 16 +++ src/ui/window.h | 4 +- 6 files changed, 95 insertions(+), 168 deletions(-) diff --git a/src/renderer/backend.h b/src/renderer/backend.h index 3162041a..8327557b 100644 --- a/src/renderer/backend.h +++ b/src/renderer/backend.h @@ -127,8 +127,8 @@ void rb_begin_surfaces2d(struct rb *rb, const struct vertex2d *verts, void rb_draw_surface2d(struct rb *rb, const struct surface2d *surf); void rb_end_surfaces2d(struct rb *rb); -void rb_begin2d(struct rb *rb); -void rb_end2d(struct rb *rb); +void rb_begin_ortho(struct rb *rb); +void rb_end_ortho(struct rb *rb); void rb_begin_frame(struct rb *rb); void rb_end_frame(struct rb *rb); diff --git a/src/renderer/gl_backend.c b/src/renderer/gl_backend.c index 65774b35..99292074 100644 --- a/src/renderer/gl_backend.c +++ b/src/renderer/gl_backend.c @@ -580,7 +580,7 @@ void rb_draw_surface2d(struct rb *rb, const struct surface2d *surf) { void rb_end_surfaces2d(struct rb *rb) {} -void rb_begin2d(struct rb *rb) { +void rb_begin_ortho(struct rb *rb) { float ortho[16]; ortho[0] = 2.0f / (float)rb->window->width; @@ -614,7 +614,7 @@ void rb_begin2d(struct rb *rb) { glUniform1i(rb_get_uniform(rb, UNIFORM_DIFFUSEMAP), MAP_DIFFUSE); } -void rb_end2d(struct rb *rb) { +void rb_end_ortho(struct rb *rb) { rb_set_scissor_test(rb, false); } diff --git a/src/ui/microprofile.cc b/src/ui/microprofile.cc index e6f71f4f..88f9d7c0 100644 --- a/src/ui/microprofile.cc +++ b/src/ui/microprofile.cc @@ -57,7 +57,7 @@ static void mp_onpostpaint(void *data) { // render the surfaces struct rb *rb = mp->window->rb; - rb_begin2d(rb); + rb_begin_ortho(rb); rb_begin_surfaces2d(rb, mp->verts, mp->num_verts, nullptr, 0); for (int i = 0; i < mp->num_surfs; i++) { @@ -66,7 +66,7 @@ static void mp_onpostpaint(void *data) { } rb_end_surfaces2d(rb); - rb_end2d(rb); + rb_end_ortho(rb); // reset surfaces mp->num_surfs = 0; diff --git a/src/ui/nuklear.c b/src/ui/nuklear.c index d7340941..e5159ba9 100644 --- a/src/ui/nuklear.c +++ b/src/ui/nuklear.c @@ -2,7 +2,6 @@ #include "ui/nuklear.h" #include "core/core.h" #include "core/string.h" -#include "renderer/backend.h" #include "ui/window.h" #define NK_IMPLEMENTATION @@ -11,77 +10,30 @@ static void nuklear_onprepaint(void *data) { struct nuklear *nk = data; - /*int width = win_width(nk->window); - int height = win_height(nk->window); - io.DisplaySize = - ImVec2(static_cast(width), static_cast(height)); + // update input state for the frame + nk_input_begin(&nk->ctx); - ImGui::NewFrame();*/ + nk_input_motion(&nk->ctx, nk->mousex, nk->mousey); + nk_input_button(&nk->ctx, NK_BUTTON_LEFT, nk->mousex, nk->mousey, nk->mouse_down[0]); + nk_input_button(&nk->ctx, NK_BUTTON_MIDDLE, nk->mousex, nk->mousey, nk->mouse_down[1]); + nk_input_button(&nk->ctx, NK_BUTTON_RIGHT, nk->mousex, nk->mousey, nk->mouse_down[2]); + + nk_input_end(&nk->ctx); } static void nuklear_onpostpaint(void *data) { struct nuklear *nk = data; struct rb *rb = nk->window->rb; - /*// if there are any focused items, enable text input - win_enable_text_input(nk->window, ImGui::IsAnyItemActive()); + // // if there are any focused items, enable text input + // win_enable_text_input(nk->window, ImGui::IsAnyItemActive()); - // update draw batches. note, this doesn't _actually_ render anything because - // io.RenderDrawListsFn is null - ImGui::Render(); + // convert draw list into vertex / element buffers + struct nk_buffer vbuf, ebuf; + nk_buffer_init_fixed(&vbuf, nk->vertices, sizeof(nk->vertices)); + nk_buffer_init_fixed(&ebuf, nk->elements, sizeof(nk->elements)); - // get the latest draw batches, and pass them off out the render backend - ImDrawData *draw_data = ImGui::GetDrawData(); - - rb_begin2d(rb); - - for (int i = 0; i < draw_data->CmdListsCount; ++i) { - const auto cmd_list = draw_data->CmdLists[i]; - - struct vertex2d *verts = - reinterpret_cast(cmd_list->VtxBuffer.Data); - int num_verts = cmd_list->VtxBuffer.size(); - - uint16_t *indices = cmd_list->IdxBuffer.Data; - int num_indices = cmd_list->IdxBuffer.size(); - - rb_begin_surfaces2d(rb, verts, num_verts, indices, num_indices); - - int index_offset = 0; - - for (int j = 0; j < cmd_list->CmdBuffer.size(); ++j) { - const auto &cmd = cmd_list->CmdBuffer[j]; - - struct surface2d surf; - surf.prim_type = PRIM_TRIANGLES; - surf.texture = static_cast( - reinterpret_cast(cmd.TextureId)); - surf.src_blend = BLEND_SRC_ALPHA; - surf.dst_blend = BLEND_ONE_MINUS_SRC_ALPHA; - surf.scissor = true; - surf.scissor_rect[0] = cmd.ClipRect.x; - surf.scissor_rect[1] = io.DisplaySize.y - cmd.ClipRect.w; - surf.scissor_rect[2] = cmd.ClipRect.z - cmd.ClipRect.x; - surf.scissor_rect[3] = cmd.ClipRect.w - cmd.ClipRect.y; - surf.first_vert = index_offset; - surf.num_verts = cmd.ElemCount; - - rb_draw_surface2d(rb, &surf); - - index_offset += cmd.ElemCount; - } - - rb_end_surfaces2d(rb); - } - - rb_end2d(rb);*/ - - const struct nk_draw_command *cmd; - const nk_draw_index *offset = NULL; - - /* fill converting configuration */ - struct nk_convert_config config; - memset(&config, 0, sizeof(config)); + struct nk_convert_config config = {}; config.global_alpha = 1.0f; config.shape_AA = NK_ANTI_ALIASING_ON; config.line_AA = NK_ANTI_ALIASING_ON; @@ -90,101 +42,90 @@ static void nuklear_onpostpaint(void *data) { config.arc_segment_count = 22; config.null = nk->null; - /* setup buffers to load vertices and elements */ - static struct vertex2d vertices[1024 * 10]; - static uint16_t elements[1024 * 10]; - - struct nk_buffer vbuf, ebuf; - nk_buffer_init_fixed(&vbuf, vertices, (size_t)sizeof(vertices)); - nk_buffer_init_fixed(&ebuf, elements, (size_t)sizeof(elements)); nk_convert(&nk->ctx, &nk->cmds, &vbuf, &ebuf, &config); - rb_begin2d(rb); + // bind buffers + rb_begin_ortho(rb); + rb_begin_surfaces2d(rb, nk->vertices, nk->ctx.draw_list.vertex_count, + nk->elements, nk->ctx.draw_list.element_count); - rb_begin_surfaces2d(rb, vertices, nk->ctx.draw_list.vertex_count, elements, - nk->ctx.draw_list.element_count); + // pass each draw command off to the render backend + const struct nk_draw_command *cmd = NULL; + int offset = 0; + + struct surface2d surf = {}; + surf.prim_type = PRIM_TRIANGLES; + surf.src_blend = BLEND_SRC_ALPHA; + surf.dst_blend = BLEND_ONE_MINUS_SRC_ALPHA; + surf.scissor = true; - int n = 0; - /* iterate over and execute each draw command */ nk_draw_foreach(cmd, &nk->ctx, &nk->cmds) { if (!cmd->elem_count) { continue; } - printf("%d\n", cmd->elem_count); - - struct surface2d surf; - surf.prim_type = PRIM_TRIANGLES; surf.texture = (texture_handle_t)cmd->texture.id; - surf.src_blend = BLEND_SRC_ALPHA; - surf.dst_blend = BLEND_ONE_MINUS_SRC_ALPHA; - surf.scissor = true; surf.scissor_rect[0] = cmd->clip_rect.x; surf.scissor_rect[1] = nk->window->height - (cmd->clip_rect.y + cmd->clip_rect.h); surf.scissor_rect[2] = cmd->clip_rect.w; surf.scissor_rect[3] = cmd->clip_rect.h; - surf.first_vert = n; + surf.first_vert = offset; surf.num_verts = cmd->elem_count; rb_draw_surface2d(rb, &surf); - /*glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); - glScissor( - (GLint)(cmd->clip_rect.x * scale.x), - (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * - scale.y), - (GLint)(cmd->clip_rect.w * scale.x), - (GLint)(cmd->clip_rect.h * scale.y)); - glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, - offset);*/ - - n += cmd->elem_count; offset += cmd->elem_count; } - nk_clear(&nk->ctx); - rb_end2d(rb); + rb_end_surfaces2d(rb); + rb_end_ortho(rb); + + // reset mouse wheel state as it won't be reset through any event + nk->mouse_wheel = 0; } static void nuklear_onkeydown(void *data, enum keycode code, int16_t value) { struct nuklear *nk = data; - /*if (code == K_MWHEELUP) { - io.MouseWheel = 1.0f; + if (code == K_MWHEELUP) { + nk->mouse_wheel = 1; } else if (code == K_MWHEELDOWN) { - io.MouseWheel = -1.0f; + nk->mouse_wheel = -1; } else if (code == K_MOUSE1) { - io.MouseDown[0] = !!value; + nk->mouse_down[0] = !!value; } else if (code == K_MOUSE2) { - io.MouseDown[1] = !!value; + nk->mouse_down[1] = !!value; } else if (code == K_MOUSE3) { - io.MouseDown[2] = !!value; + nk->mouse_down[2] = !!value; } else if (code == K_LALT || code == K_RALT) { - nk->alt[code == K_LALT ? 0 : 1] = !!value; - io.KeyAlt = nk->alt[0] || nk->alt[1]; + //nk->alt[code == K_LALT ? 0 : 1] = !!value; + //io.KeyAlt = nk->alt[0] || nk->alt[1]; } else if (code == K_LCTRL || code == K_RCTRL) { - nk->ctrl[code == K_LCTRL ? 0 : 1] = !!value; - io.KeyCtrl = nk->ctrl[0] || nk->ctrl[1]; + //nk->ctrl[code == K_LCTRL ? 0 : 1] = !!value; + //io.KeyCtrl = nk->ctrl[0] || nk->ctrl[1]; } else if (code == K_LSHIFT || code == K_RSHIFT) { - nk->shift[code == K_LSHIFT ? 0 : 1] = !!value; - io.KeyShift = nk->shift[0] || nk->shift[1]; + //nk->shift[code == K_LSHIFT ? 0 : 1] = !!value; + //io.KeyShift = nk->shift[0] || nk->shift[1]; } else { - io.KeysDown[code] = !!value; - }*/ + //io.KeysDown[code] = !!value; + } } static void nuklear_ontextinput(void *data, const char *text) { struct nuklear *nk = data; - // io.AddInputCharactersUTF8(text); + nk_glyph glyph; + memcpy(glyph, text, NK_UTF_SIZE); + nk_input_glyph(&nk->ctx, glyph); } static void nuklear_onmousemove(void *data, int x, int y) { struct nuklear *nk = data; - // io.MousePos = ImVec2((float)x, (float)y); + nk->mousex = x; + nk->mousey = y; } struct nk_context *nuklear_context(struct nuklear *nk) { @@ -204,63 +145,31 @@ struct nuklear *nuklear_create(struct window *window) { nk->window = window; nk->listener = win_add_listener(nk->window, &callbacks, nk); - /*// setup key mapping - io.KeyMap[ImGuiKey_Tab] = K_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = K_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = K_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = K_UP; - io.KeyMap[ImGuiKey_DownArrow] = K_DOWN; - io.KeyMap[ImGuiKey_PageUp] = K_PAGEUP; - io.KeyMap[ImGuiKey_PageDown] = K_PAGEDOWN; - io.KeyMap[ImGuiKey_Home] = K_HOME; - io.KeyMap[ImGuiKey_End] = K_END; - io.KeyMap[ImGuiKey_Delete] = K_DELETE; - io.KeyMap[ImGuiKey_Backspace] = K_BACKSPACE; - io.KeyMap[ImGuiKey_Enter] = K_RETURN; - io.KeyMap[ImGuiKey_Escape] = K_ESCAPE; - io.KeyMap[ImGuiKey_A] = 'a'; - io.KeyMap[ImGuiKey_C] = 'c'; - io.KeyMap[ImGuiKey_V] = 'v'; - io.KeyMap[ImGuiKey_X] = 'x'; - io.KeyMap[ImGuiKey_Y] = 'y'; - io.KeyMap[ImGuiKey_Z] = 'z'; - - // setup misc callbacks ImGui relies on - io.RenderDrawListsFn = nullptr; - io.SetClipboardTextFn = nullptr; - io.GetClipboardTextFn = nullptr; - - // register font in backend - uint8_t *pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - texture_handle_t handle = - rb_register_texture(rb, PXL_RGBA, FILTER_BILINEAR, WRAP_REPEAT, - WRAP_REPEAT, false, width, height, pixels); - io.Fonts->TexID = reinterpret_cast(static_cast(handle));*/ - - nk_init_default(&nk->ctx, 0); - nk_buffer_init_default(&nk->cmds); - - struct rb *rb = nk->window->rb; + // create default font texture nk_font_atlas_init_default(&nk->atlas); nk_font_atlas_begin(&nk->atlas); - int w, h; - const void *image = - nk_font_atlas_bake(&nk->atlas, &w, &h, NK_FONT_ATLAS_RGBA32); - texture_handle_t handle = - rb_register_texture(rb, PXL_RGBA, FILTER_BILINEAR, WRAP_REPEAT, - WRAP_REPEAT, false, w, h, image); + struct nk_font *font = nk_font_atlas_add_default(&nk->atlas, 13.0f, NULL); + int font_width, font_height; + const void *font_data = nk_font_atlas_bake( + &nk->atlas, &font_width, &font_height, NK_FONT_ATLAS_RGBA32); + texture_handle_t handle = rb_register_texture( + nk->window->rb, PXL_RGBA, FILTER_BILINEAR, WRAP_REPEAT, WRAP_REPEAT, + false, font_width, font_height, font_data); nk_font_atlas_end(&nk->atlas, nk_handle_id((int)handle), &nk->null); - if (nk->atlas.default_font) { - nk_style_set_font(&nk->ctx, &nk->atlas.default_font->handle); - } + + // initialize nuklear context + nk_init_default(&nk->ctx, &font->handle); + nk_buffer_init_default(&nk->cmds); + return nk; } void nuklear_destroy(struct nuklear *nk) { nk_buffer_free(&nk->cmds); + nk_font_atlas_clear(&nk->atlas); + nk_free(&nk->ctx); + win_remove_listener(nk->window, nk->listener); + free(nk); } diff --git a/src/ui/nuklear.h b/src/ui/nuklear.h index 22724cc4..51e71b84 100644 --- a/src/ui/nuklear.h +++ b/src/ui/nuklear.h @@ -11,16 +11,32 @@ #define NK_INCLUDE_DEFAULT_FONT #include +#include "renderer/backend.h" + struct window; struct window_listener; +#define NK_MAX_VERTICES 4096 +#define NK_MAX_ELEMENTS 16384 + struct nuklear { struct window *window; struct window_listener *listener; + + // struct nk_context ctx; struct nk_buffer cmds; struct nk_font_atlas atlas; struct nk_draw_null_texture null; + + // render buffers + struct vertex2d vertices[NK_MAX_VERTICES]; + uint16_t elements[NK_MAX_ELEMENTS]; + + // input state + int mousex, mousey; + int mouse_wheel; + bool mouse_down[3]; bool alt[2]; bool ctrl[2]; bool shift[2]; diff --git a/src/ui/window.h b/src/ui/window.h index e928f752..403bb712 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -38,11 +38,13 @@ struct window_listener { }; struct window { - // state is read-only to the public + // public struct SDL_Window *handle; struct rb *rb; struct nuklear *nk; struct microprofile *mp; + + // read only int width; int height; bool main_menu;