Ver código fonte

sdl_gpu skeleton

ryan zmuda 10 meses atrás
pai
commit
079d3b681d

+ 1 - 0
demo/sdl_gpu/.gitignore

@@ -0,0 +1 @@
+build

+ 34 - 0
demo/sdl_gpu/CMakeLists.txt

@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.16)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE INTERNAL "")
+
+# CMAKE Modules
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+project(nuklear_sdl_gpu)
+
+set(EXECUTABLE_NAME ${PROJECT_NAME})
+
+# The SDL java code is hardcoded to load libmain.so on android, so we need to change EXECUTABLE_NAME
+if (ANDROID)
+	set(EXECUTABLE_NAME main)
+	add_library(${EXECUTABLE_NAME} SHARED)
+else()
+	add_executable(${EXECUTABLE_NAME})
+endif()
+
+# Add your sources to the target
+target_sources(${EXECUTABLE_NAME} PRIVATE main.c)
+
+find_package(SDL3 REQUIRED)
+
+# TODO: remove libm and fallback on Nuklear floor()
+target_link_libraries(${EXECUTABLE_NAME} PUBLIC SDL3::SDL3 m)
+
+# Nuklear Include Directory
+target_include_directories(${EXECUTABLE_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../..)
+
+# on Visual Studio, set our app as the default project
+set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT "${EXECUTABLE_NAME}")

+ 8 - 0
demo/sdl_gpu/cmake/FindSDL3.cmake

@@ -0,0 +1,8 @@
+include(FetchContent)
+FetchContent_Declare(
+    SDL3
+    GIT_REPOSITORY  https://github.com/libsdl-org/SDL.git
+    GIT_TAG         release-3.2.2
+    GIT_SHALLOW     TRUE
+)
+FetchContent_MakeAvailable(SDL3)

+ 245 - 0
demo/sdl_gpu/main.c

@@ -0,0 +1,245 @@
+/* nuklear - public domain */
+#include <stdio.h>
+#include <stddef.h> /* offsetof TODO: sdl2_renderer didn't need this header? */
+
+#define SDL_MAIN_USE_CALLBACKS
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SDL_GPU_IMPLEMENTATION
+#define NK_INCLUDE_STANDARD_BOOL
+#include "nuklear.h"
+#include "nuklear_sdl_gpu.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+/* ===============================================================
+ *
+ *                          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 defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_CANVAS */
+#define INCLUDE_OVERVIEW
+/*#define INCLUDE_CONFIGURATOR */
+/*#define INCLUDE_NODE_EDITOR */
+
+#define INCLUDE_ALL
+
+#ifdef INCLUDE_ALL
+    #define INCLUDE_STYLE
+    #define INCLUDE_CALCULATOR
+    #define INCLUDE_CANVAS
+    #define INCLUDE_OVERVIEW
+    /* #define INCLUDE_CONFIGURATOR */
+    #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+    #include "../../demo/common/style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+    #include "../../demo/common/calculator.c"
+#endif
+#ifdef INCLUDE_CANVAS
+    #include "../../demo/common/canvas.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+    #include "../../demo/common/overview.c"
+#endif
+/*
+#ifdef INCLUDE_CONFIGURATOR
+    #include "../../demo/common/style_configurator.c"
+#endif
+*/
+#ifdef INCLUDE_NODE_EDITOR
+    #include "../../demo/common/node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+
+typedef struct AppContext {
+    SDL_Window* window;
+    SDL_Renderer* renderer;
+} AppContext;
+
+struct nk_context * ctx;
+struct nk_colorf bg;
+
+SDL_AppResult SDL_Fail(){
+    SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
+    return SDL_APP_FAILURE;
+}
+
+SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
+    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
+        return SDL_Fail();
+    }
+
+    AppContext* appContext = (AppContext*)SDL_malloc(sizeof(AppContext));
+    if (appContext == NULL) {
+        return SDL_Fail();
+    }
+
+    if (!SDL_CreateWindowAndRenderer("Nuklear: SDL3 GPU", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &appContext->window, &appContext->renderer)) {
+        SDL_free(appContext);
+        return SDL_Fail();
+    }
+
+    SDL_StartTextInput(appContext->window);
+
+    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+
+    *appstate = appContext;
+
+    float font_scale = 1;
+
+    {
+        int render_w, render_h;
+        int window_w, window_h;
+        float scale_x, scale_y;
+        SDL_GetCurrentRenderOutputSize(appContext->renderer, &render_w, &render_h);
+        SDL_GetWindowSize(appContext->window, &window_w, &window_h);
+        scale_x = (float)(render_w) / (float)(window_w);
+        scale_y = (float)(render_h) / (float)(window_h);
+        SDL_SetRenderScale(appContext->renderer, scale_x, scale_y);
+        font_scale = scale_y;
+    }
+
+    ctx = nk_sdl_init(appContext->window, appContext->renderer);
+
+    {
+        struct nk_font_atlas *atlas;
+        struct nk_font_config config = nk_font_config(0);
+        struct nk_font *font;
+
+        /* set up the font atlas and add desired font; note that font sizes are
+         * multiplied by font_scale to produce better results at higher DPIs */
+        nk_sdl_font_stash_begin(&atlas);
+        font = nk_font_atlas_add_default(atlas, 13 * font_scale, &config);
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14 * font_scale, &config);*/
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16 * font_scale, &config);*/
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13 * font_scale, &config);*/
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12 * font_scale, &config);*/
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10 * font_scale, &config);*/
+        /*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13 * font_scale, &config);*/
+        nk_sdl_font_stash_end();
+
+        /* this hack makes the font appear to be scaled down to the desired
+         * size and is only necessary when font_scale > 1 */
+        font->handle.height /= font_scale;
+        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+        nk_style_set_font(ctx, &font->handle);
+    }
+
+    return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event* event) {
+    AppContext* app = (AppContext*)appstate;
+
+    switch (event->type) {
+        case SDL_EVENT_QUIT:
+            return SDL_APP_SUCCESS;
+    }
+
+    nk_sdl_handle_event(event);
+
+    return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate) {
+    nk_input_end(ctx);
+    AppContext* app = (AppContext*)appstate;
+
+    /* GUI */
+    if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+        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"))
+            printf("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, 25, 1);
+        nk_property_int(ctx, "Compression:", 0, &property, 1000, 1, 1);
+
+        nk_layout_row_dynamic(ctx, 20, 1);
+        nk_label(ctx, "background:", NK_TEXT_LEFT);
+        nk_layout_row_dynamic(ctx, 25, 1);
+        if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+            nk_layout_row_dynamic(ctx, 120, 1);
+            bg = nk_color_picker(ctx, bg, NK_RGBA);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+            bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+            bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+            bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+            nk_combo_end(ctx);
+        }
+    }
+    nk_end(ctx);
+
+    /* -------------- EXAMPLES ---------------- */
+    #ifdef INCLUDE_CALCULATOR
+        calculator(ctx);
+    #endif
+    #ifdef INCLUDE_CANVAS
+    canvas(ctx);
+    #endif
+    #ifdef INCLUDE_OVERVIEW
+        overview(ctx);
+    #endif
+    #ifdef INCLUDE_CONFIGURATOR
+        style_configurator(ctx, color_table);
+    #endif
+    #ifdef INCLUDE_NODE_EDITOR
+        node_editor(ctx);
+    #endif
+    /* ----------------------------------------- */
+
+    SDL_SetRenderDrawColor(app->renderer, 255, 0, 255, SDL_ALPHA_OPAQUE);
+    SDL_RenderClear(app->renderer);
+
+    nk_sdl_render(NK_ANTI_ALIASING_ON);
+
+    SDL_RenderPresent(app->renderer);
+
+    nk_input_begin(ctx);
+    return SDL_APP_CONTINUE;
+}
+
+void SDL_AppQuit(void* appstate, SDL_AppResult result) {
+    AppContext* app = (AppContext*)appstate;
+
+    if (app) {
+        SDL_DestroyRenderer(app->renderer);
+        SDL_DestroyWindow(app->window);
+        SDL_free(app);
+    }
+
+    SDL_Quit();
+}

+ 316 - 0
demo/sdl_gpu/nuklear_sdl_gpu.h

@@ -0,0 +1,316 @@
+/*
+ * Nuklear - 4.9.4 - public domain
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GPU_H_
+#define NK_SDL_GPU_H_
+
+NK_API struct nk_context*   nk_sdl_init(SDL_Window *win, SDL_Renderer *renderer);
+NK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void                 nk_sdl_font_stash_end(void);
+NK_API int                  nk_sdl_handle_event(SDL_Event *evt);
+NK_API void                 nk_sdl_render(enum nk_anti_aliasing);
+NK_API void                 nk_sdl_shutdown(void);
+
+#if SDL_MAJOR_VERSION < 3
+#error "nuklear_sdl_gpu requires at least SDL 3.0.0"
+#endif
+
+#endif /* NK_SDL_GPU_H_ */
+
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GPU_IMPLEMENTATION
+
+struct nk_sdl_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture tex_null;
+    SDL_Texture *font_tex;
+};
+
+struct nk_sdl_vertex {
+    float position[2];
+    float uv[2];
+    float col[4];
+};
+
+static struct nk_sdl {
+    SDL_Window *win;
+    SDL_Renderer *renderer;
+    struct nk_sdl_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+} sdl;
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+
+    SDL_Texture *g_SDLFontTexture = SDL_CreateTexture(sdl.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);
+    if (g_SDLFontTexture == NULL) {
+        SDL_Log("error creating texture");
+        return;
+    }
+    SDL_UpdateTexture(g_SDLFontTexture, NULL, image, 4 * width);
+    SDL_SetTextureBlendMode(g_SDLFontTexture, SDL_BLENDMODE_BLEND);
+    dev->font_tex = g_SDLFontTexture;
+}
+
+NK_API void
+nk_sdl_render(enum nk_anti_aliasing AA)
+{
+    /* setup global state */
+    struct nk_sdl_device *dev = &sdl.ogl;
+
+    {
+        SDL_Rect saved_clip;
+        bool clipping_enabled;
+        int vs = sizeof(struct nk_sdl_vertex);
+        size_t vp = offsetof(struct nk_sdl_vertex, position);
+        size_t vt = offsetof(struct nk_sdl_vertex, uv);
+        size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        const nk_draw_index *offset = NULL;
+        struct nk_buffer vbuf, ebuf;
+
+        /* fill converting configuration */
+        struct nk_convert_config config;
+        static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+            {NK_VERTEX_POSITION,    NK_FORMAT_FLOAT,                NK_OFFSETOF(struct nk_sdl_vertex, position)},
+            {NK_VERTEX_TEXCOORD,    NK_FORMAT_FLOAT,                NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+            {NK_VERTEX_COLOR,       NK_FORMAT_R32G32B32A32_FLOAT,   NK_OFFSETOF(struct nk_sdl_vertex, col)},
+            {NK_VERTEX_LAYOUT_END}
+        };
+        NK_MEMSET(&config, 0, sizeof(config));
+        config.vertex_layout = vertex_layout;
+        config.vertex_size = sizeof(struct nk_sdl_vertex);
+        config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+        config.tex_null = dev->tex_null;
+        config.circle_segment_count = 22;
+        config.curve_segment_count = 22;
+        config.arc_segment_count = 22;
+        config.global_alpha = 1.0f;
+        config.shape_AA = AA;
+        config.line_AA = AA;
+
+        /* convert shapes into vertexes */
+        nk_buffer_init_default(&vbuf);
+        nk_buffer_init_default(&ebuf);
+        nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+        /* iterate over and execute each draw command */
+        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+
+        clipping_enabled = SDL_RenderClipEnabled(sdl.renderer);
+        SDL_GetRenderClipRect(sdl.renderer, &saved_clip);
+
+        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds)
+        {
+            if (!cmd->elem_count) continue;
+
+            {
+                SDL_Rect r;
+                r.x = cmd->clip_rect.x;
+                r.y = cmd->clip_rect.y;
+                r.w = cmd->clip_rect.w;
+                r.h = cmd->clip_rect.h;
+                SDL_SetRenderClipRect(sdl.renderer, &r);
+            }
+
+            {
+                const void *vertices = nk_buffer_memory_const(&vbuf);
+
+                SDL_RenderGeometryRaw(sdl.renderer,
+                        (SDL_Texture *)cmd->texture.ptr,
+                        (const float*)((const nk_byte*)vertices + vp), vs,
+                        (const SDL_FColor*)((const nk_byte*)vertices + vc), vs,
+                        (const float*)((const nk_byte*)vertices + vt), vs,
+                        (vbuf.needed / vs),
+                        (void *) offset, cmd->elem_count, 2);
+
+                offset += cmd->elem_count;
+            }
+        }
+
+        SDL_SetRenderClipRect(sdl.renderer, &saved_clip);
+        if (!clipping_enabled) {
+            SDL_SetRenderClipRect(sdl.renderer, NULL);
+        }
+
+        nk_clear(&sdl.ctx);
+        nk_buffer_clear(&dev->cmds);
+        nk_buffer_free(&vbuf);
+        nk_buffer_free(&ebuf);
+    }
+}
+
+static void
+nk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    const char *text = SDL_GetClipboardText();
+    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+    (void)usr;
+}
+
+static void
+nk_sdl_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';
+    SDL_SetClipboardText(str);
+    free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win, SDL_Renderer *renderer)
+{
+    sdl.win = win;
+    sdl.renderer = renderer;
+    nk_init_default(&sdl.ctx, 0);
+    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;
+    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;
+    sdl.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_buffer_init_default(&sdl.ogl.cmds);
+    return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&sdl.atlas);
+    nk_font_atlas_begin(&sdl.atlas);
+    *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+    const void *image; int w, h;
+    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sdl_device_upload_atlas(image, w, h);
+    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(sdl.ogl.font_tex), &sdl.ogl.tex_null);
+    if (sdl.atlas.default_font)
+        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+    struct nk_context *ctx = &sdl.ctx;
+
+    switch(evt->type)
+    {
+        case SDL_EVENT_KEY_UP: /* KEYUP & KEYDOWN share same routine */
+        case SDL_EVENT_KEY_DOWN:
+            {
+                int down = evt->type == SDL_EVENT_KEY_DOWN;
+                const bool* state = SDL_GetKeyboardState(0);
+                switch(evt->key.key)
+                {
+                    case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */
+                    case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;
+                    case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;
+                    case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;
+                    case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;
+                    case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;
+                    case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);
+                                         nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;
+                    case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);
+                                         nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;
+                    case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;
+                    case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;
+                    case SDLK_Z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_R:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_C:         nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_V:         nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_X:         nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_B:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_E:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]); break;
+                    case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;
+                    case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;
+                    case SDLK_LEFT:
+                        if (state[SDL_SCANCODE_LCTRL])
+                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+                        else nk_input_key(ctx, NK_KEY_LEFT, down);
+                        break;
+                    case SDLK_RIGHT:
+                        if (state[SDL_SCANCODE_LCTRL])
+                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+                        else nk_input_key(ctx, NK_KEY_RIGHT, down);
+                        break;
+                }
+                return 1;
+            }
+
+        case SDL_EVENT_MOUSE_BUTTON_UP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */
+        case SDL_EVENT_MOUSE_BUTTON_DOWN:
+            {
+                int down = evt->button.down;
+                const int x = evt->button.x, y = evt->button.y;
+                switch(evt->button.button)
+                {
+                    case SDL_BUTTON_LEFT:
+                        if (evt->button.clicks > 1)
+                            nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
+                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); break;
+                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;
+                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;
+                }
+            }
+            return 1;
+
+        case SDL_EVENT_MOUSE_MOTION:
+            if (ctx->input.mouse.grabbed) {
+                int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+                nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+            }
+            else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+            return 1;
+
+        case SDL_EVENT_TEXT_INPUT:
+            {
+                nk_glyph glyph;
+                memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+                nk_input_glyph(ctx, glyph);
+            }
+            return 1;
+
+        case SDL_EVENT_MOUSE_WHEEL:
+            nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
+            return 1;
+    }
+    return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    nk_font_atlas_clear(&sdl.atlas);
+    nk_free(&sdl.ctx);
+    SDL_DestroyTexture(dev->font_tex);
+    /* glDeleteTextures(1, &dev->font_tex); */
+    nk_buffer_free(&dev->cmds);
+    memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif /* NK_SDL_GPU_IMPLEMENTATION */