Browse Source

Merge branch 'master' of github.com:Immediate-Mode-UI/Nuklear into demo-disable-optimization

Rob Loach 10 months ago
parent
commit
9e6f55d6f2
77 changed files with 10817 additions and 5309 deletions
  1. 1 0
      .gitignore
  2. 90 0
      Makefile
  3. 1 1
      demo/allegro5/main.c
  4. 3 2
      demo/common/overview.c
  5. 439 191
      demo/common/style.c
  6. 1 1
      demo/d3d11/main.c
  7. 22 0
      demo/d3d11/nuklear_d3d11.h
  8. 1 1
      demo/d3d12/main.c
  9. 1 1
      demo/d3d9/main.c
  10. 1 1
      demo/gdi/main.c
  11. 1 1
      demo/gdip/main.c
  12. 1 1
      demo/glfw_opengl3/main.c
  13. 1 1
      demo/glfw_opengl4/main.c
  14. 39 8
      demo/glfw_vulkan/main.c
  15. 2 5
      demo/glfw_vulkan/nuklear_glfw_vulkan.h
  16. 9 6
      demo/glfw_vulkan/src/nuklear_glfw_vulkan.in.h
  17. 1 1
      demo/rawfb/sdl/main.c
  18. 1 1
      demo/rawfb/wayland/main.c
  19. 1 1
      demo/rawfb/x11/Makefile
  20. 1 1
      demo/rawfb/x11/main.c
  21. 1 1
      demo/sdl_opengl2/Makefile
  22. 2 2
      demo/sdl_opengl2/main.c
  23. 1 1
      demo/sdl_opengl3/Makefile
  24. 1 1
      demo/sdl_opengl3/main.c
  25. 1 1
      demo/sdl_opengles2/Makefile
  26. 1 1
      demo/sdl_opengles2/main.c
  27. 1 1
      demo/sdl_renderer/Makefile
  28. 1 1
      demo/sdl_renderer/main.c
  29. 3 0
      demo/sdl_vulkan/.gitignore
  30. 30 0
      demo/sdl_vulkan/Makefile
  31. 52 0
      demo/sdl_vulkan/README.md
  32. 2251 0
      demo/sdl_vulkan/main.c
  33. 1648 0
      demo/sdl_vulkan/nuklear_sdl_vulkan.h
  34. 12 0
      demo/sdl_vulkan/shaders/demo.frag
  35. 10 0
      demo/sdl_vulkan/shaders/demo.vert
  36. 11 0
      demo/sdl_vulkan/src/Makefile
  37. 5 0
      demo/sdl_vulkan/src/README.md
  38. 1425 0
      demo/sdl_vulkan/src/nuklear_sdl_vulkan.in.h
  39. 13 0
      demo/sdl_vulkan/src/nuklearshaders/nuklear.frag
  40. 23 0
      demo/sdl_vulkan/src/nuklearshaders/nuklear.vert
  41. 1 1
      demo/sfml_opengl2/main.cpp
  42. 1 1
      demo/sfml_opengl3/main.cpp
  43. 1 1
      demo/x11/Makefile
  44. 1 1
      demo/x11/main.c
  45. 3 3
      demo/x11_opengl2/Makefile
  46. 1 1
      demo/x11_opengl2/main.c
  47. 3 3
      demo/x11_opengl3/Makefile
  48. 1 1
      demo/x11_opengl3/main.c
  49. 1 1
      demo/x11_xft/Makefile
  50. 1 1
      demo/x11_xft/main.c
  51. 1 1
      demo/xcb_cairo/main.c
  52. 2739 0
      doc/Doxyfile
  53. 0 26
      doc/Makefile
  54. 0 2
      doc/build.sh
  55. 0 2974
      doc/index.html
  56. 0 11
      doc/nuklear.html
  57. 0 141
      doc/stddoc.c
  58. 1100 1068
      nuklear.h
  59. 0 216
      src/HEADER
  60. 216 0
      src/HEADER.md
  61. 3 1
      src/build.py
  62. 582 560
      src/nuklear.h
  63. 2 3
      src/nuklear_buffer.c
  64. 2 3
      src/nuklear_color.c
  65. 2 3
      src/nuklear_combo.c
  66. 3 4
      src/nuklear_draw.c
  67. 1 2
      src/nuklear_font.c
  68. 3 4
      src/nuklear_internal.h
  69. 8 8
      src/nuklear_layout.c
  70. 1 1
      src/nuklear_popup.c
  71. 2 3
      src/nuklear_string.c
  72. 1 2
      src/nuklear_style.c
  73. 1 2
      src/nuklear_table.c
  74. 9 9
      src/nuklear_widget.c
  75. 16 16
      src/nuklear_window.c
  76. 1 1
      src/paq.bat
  77. 1 1
      src/paq.sh

+ 1 - 0
.gitignore

@@ -6,6 +6,7 @@ docs/xml
 docs/build
 docs/src
 doc/doc*
+doc/*
 *.tmp
 *.swo
 *.swp

+ 90 - 0
Makefile

@@ -0,0 +1,90 @@
+
+######################################################################################
+##  								 SETTINGS                                       ##
+######################################################################################
+
+## path stuff
+DOCS_PATH:=./doc
+DEMO_PATH=demo
+SRC_PATH=src
+
+
+## Documents settings
+DOXYFILE:=$(DOCS_PATH)/Doxyfile
+
+
+## HEADER file packing settings
+## note: source file paths are prefixed later, no need to add prefix here; just
+## give it the name.
+MACRO = NK
+INTRO =  HEADER.md
+PUB = nuklear.h
+OUTPUT = nuklear.h
+
+PRIV1 = nuklear_internal.h nuklear_math.c nuklear_util.c nuklear_color.c nuklear_utf8.c nuklear_buffer.c nuklear_string.c nuklear_draw.c nuklear_vertex.c 
+
+EXTERN =  stb_rect_pack.h stb_truetype.h 
+
+PRIV2 = nuklear_font.c nuklear_input.c nuklear_style.c nuklear_context.c nuklear_pool.c nuklear_page_element.c nuklear_table.c nuklear_panel.c nuklear_window.c nuklear_popup.c nuklear_contextual.c nuklear_menu.c nuklear_layout.c nuklear_tree.c nuklear_group.c nuklear_list_view.c nuklear_widget.c nuklear_text.c nuklear_image.c nuklear_9slice.c nuklear_button.c nuklear_toggle.c nuklear_selectable.c nuklear_slider.c nuklear_knob.c nuklear_progress.c nuklear_scrollbar.c nuklear_text_editor.c nuklear_edit.c nuklear_property.c nuklear_chart.c nuklear_color_picker.c nuklear_combo.c nuklear_tooltip.c
+
+OUTRO = LICENSE CHANGELOG CREDITS
+
+## Demo settings
+DEMO_LIST = $(shell find $(DEMO_PATH) -type f -name Makefile -printf "%h ")
+
+######################################################################################
+##  								 RECIPES                                        ##
+######################################################################################
+
+
+.PHONY: usage all demos $(DEMO_LIST)
+
+usage:
+	echo "make docs		to create documentation"
+	echo "make nuke		to rebuild the single header nuklear.h from source"
+	echo "make demos	to build all of the demos
+	echo "make all 		to re-pack the header and create documentation"
+
+all: docs nuke demos 
+demos: $(DEMO_LIST)
+
+
+########################################################################################
+##   Nuklear.h
+
+nuke: $(addprefix $(SRC_PATH)/, $(SRC))
+	python3 $(SRC_PATH)/build.py --macro $(MACRO) --intro $(addprefix $(SRC_PATH)/, $(INTRO)) --pub $(addprefix $(SRC_PATH)/, $(PUB)) --priv1 "$(addprefix $(SRC_PATH)/, $(PRIV1))" --extern "$(addprefix $(SRC_PATH)/, $(EXTERN))" --priv2 "$(addprefix $(SRC_PATH)/, $(PRIV2))" --outro "$(addprefix $(SRC_PATH)/, $(OUTRO))" > $(OUTPUT)
+
+
+
+
+
+########################################################################################
+##   Docs
+
+docs: $(DOCS_PATH)/html/index.html 
+
+$(DOCS_PATH)/html/index.html: $(DOCS_PATH)/doxygen-awesome-css/doxygen-awesome.css $(DOXYFILE)
+	doxygen $(DOXYFILE)
+
+$(DOXYFILE):
+	doxygen -g $@
+
+$(DOCS_PATH)/doxygen-awesome-css/doxygen-awesome.css:
+	git clone https://github.com/jothepro/doxygen-awesome-css.git $(DOCS_PATH)/doxygen-awesome-css --branch v2.3.4
+
+
+
+########################################################################################
+##   Demos
+
+$(DEMO_LIST):
+	$(MAKE) -C $@
+
+
+
+########################################################################################
+##   Utility helpers
+
+clean:
+	rm -rf $(DOCS_PATH)/html $(OUTPUT)

+ 1 - 1
demo/allegro5/main.c

@@ -41,7 +41,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 3 - 2
demo/common/overview.c

@@ -18,7 +18,8 @@ overview(struct nk_context *ctx)
 
 #ifdef INCLUDE_STYLE
     /* styles */
-    static const char* themes[] = {"Black", "White", "Red", "Blue", "Dark", "Dracula"};
+    static const char* themes[] = {"Black", "White", "Red", "Blue", "Dark", "Dracula", 
+      "Catppucin Latte", "Catppucin Frappe", "Catppucin Macchiato", "Catppucin Mocha"};
     static int current_theme = 0;
 #endif
 
@@ -156,7 +157,7 @@ overview(struct nk_context *ctx)
             nk_checkbox_flags_label(ctx, "No Scrollbar", &window_flags, NK_WINDOW_NO_SCROLLBAR);
             nk_checkbox_flags_label(ctx, "Minimizable", &window_flags, NK_WINDOW_MINIMIZABLE);
             nk_checkbox_flags_label(ctx, "Scale Left", &window_flags, NK_WINDOW_SCALE_LEFT);
-			nk_checkbox_label(ctx, "Disable widgets", &disable_widgets);
+            nk_checkbox_label(ctx, "Disable widgets", &disable_widgets);
             nk_tree_pop(ctx);
         }
 

+ 439 - 191
demo/common/style.c

@@ -1,193 +1,441 @@
-enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK, THEME_DRACULA};
+enum theme {
+  THEME_BLACK,
+  THEME_WHITE,
+  THEME_RED,
+  THEME_BLUE,
+  THEME_DARK,
+  THEME_DRACULA,
+  THEME_CATPPUCCIN_LATTE,
+  THEME_CATPPUCCIN_FRAPPE,
+  THEME_CATPPUCCIN_MACCHIATO,
+  THEME_CATPPUCCIN_MOCHA
+  
+};
 
-static void
-set_style(struct nk_context *ctx, enum theme theme)
-{
-    struct nk_color table[NK_COLOR_COUNT];
-    if (theme == THEME_WHITE) {
-        table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);
-        table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);
-        table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);
-        table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);
-        table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);
-        table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);
-        table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);
-        table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);
-        table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);
-        table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);
-        table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);
-        table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);
-        table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);
-        table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);
-        table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);
-        table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);
-        table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);
-        table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
-        table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);
-        table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);
-        table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
-        table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
-        table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
-        table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
-        nk_style_from_table(ctx, table);
-    } else if (theme == THEME_RED) {
-        table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255);
-        table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215);
-        table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220);
-        table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255);
-        table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255);
-        table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255);
-        table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255);
-        table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255);
-        table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255);
-        table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255);
-        table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255);
-        table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255);
-        table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225);
-        table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255);
-        table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255);
-        table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255);
-        table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
-        table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
-        table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220);
-        table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
-        table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
-        table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
-        table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
-        nk_style_from_table(ctx, table);
-    } else if (theme == THEME_BLUE) {
-        table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255);
-        table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215);
-        table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220);
-        table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255);
-        table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255);
-        table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255);
-        table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255);
-        table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255);
-        table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255);
-        table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255);
-        table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255);
-        table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255);
-        table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255);
-        table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245);
-        table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255);
-        table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255);
-        table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255);
-        table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225);
-        table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255);
-        table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255);
-        table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255);
-        table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255);
-        table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
-        table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
-        table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255);
-        table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
-        table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
-        table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
-        table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
-        nk_style_from_table(ctx, table);
-    } else if (theme == THEME_DARK) {
-        table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
-        table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215);
-        table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
-        table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
-        table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);
-        table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);
-        table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);
-        table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);
-        table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);
-        table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
-        table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
-        table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);
-        table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);
-        table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
-        table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
-        table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
-        table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);
-        table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
-        table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
-        table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
-        table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
-        nk_style_from_table(ctx, table);
-    } else if (theme == THEME_DRACULA) {
-        struct nk_color background = nk_rgba(40, 42, 54, 255);
-        struct nk_color currentline = nk_rgba(68, 71, 90, 255);
-        struct nk_color foreground = nk_rgba(248, 248, 242, 255);
-        struct nk_color comment = nk_rgba(98, 114, 164, 255);
-        /* struct nk_color cyan = nk_rgba(139, 233, 253, 255); */
-        /* struct nk_color green = nk_rgba(80, 250, 123, 255); */
-        /* struct nk_color orange = nk_rgba(255, 184, 108, 255); */
-        struct nk_color pink = nk_rgba(255, 121, 198, 255);
-        struct nk_color purple = nk_rgba(189, 147, 249, 255);
-        /* struct nk_color red = nk_rgba(255, 85, 85, 255); */
-        /* struct nk_color yellow = nk_rgba(241, 250, 140, 255); */
-        table[NK_COLOR_TEXT] = foreground;
-        table[NK_COLOR_WINDOW] = background;
-        table[NK_COLOR_HEADER] = currentline;
-        table[NK_COLOR_BORDER] = currentline;
-        table[NK_COLOR_BUTTON] = currentline;
-        table[NK_COLOR_BUTTON_HOVER] = comment;
-        table[NK_COLOR_BUTTON_ACTIVE] = purple;
-        table[NK_COLOR_TOGGLE] = currentline;
-        table[NK_COLOR_TOGGLE_HOVER] = comment;
-        table[NK_COLOR_TOGGLE_CURSOR] = pink;
-        table[NK_COLOR_SELECT] = currentline;
-        table[NK_COLOR_SELECT_ACTIVE] = comment;
-        table[NK_COLOR_SLIDER] = background;
-        table[NK_COLOR_SLIDER_CURSOR] = currentline;
-        table[NK_COLOR_SLIDER_CURSOR_HOVER] = comment;
-        table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = comment;
-        table[NK_COLOR_PROPERTY] = currentline;
-        table[NK_COLOR_EDIT] = currentline;
-        table[NK_COLOR_EDIT_CURSOR] = foreground;
-        table[NK_COLOR_COMBO] = currentline;
-        table[NK_COLOR_CHART] = currentline;
-        table[NK_COLOR_CHART_COLOR] = comment;
-        table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = purple;
-        table[NK_COLOR_SCROLLBAR] = background;
-        table[NK_COLOR_SCROLLBAR_CURSOR] = currentline;
-        table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = comment;
-        table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = purple;
-        table[NK_COLOR_TAB_HEADER] = currentline;
-        table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
-        table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
-        table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
-        table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
-        nk_style_from_table(ctx, table);
-    } else {
-        nk_style_default(ctx);
-    }
+static void set_style(struct nk_context *ctx, enum theme theme) {
+  struct nk_color table[NK_COLOR_COUNT];
+  if (theme == THEME_WHITE) {
+    table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);
+    table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);
+    table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);
+    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);
+    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);
+    table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);
+    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);
+    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);
+    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);
+    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);
+    table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);
+    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);
+    table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);
+    table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);
+    table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
+    table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);
+    table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_RED) {
+    table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255);
+    table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215);
+    table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220);
+    table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255);
+    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255);
+    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255);
+    table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255);
+    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255);
+    table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255);
+    table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255);
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255);
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255);
+    table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225);
+    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255);
+    table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255);
+    table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255);
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
+    table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
+    table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220);
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_BLUE) {
+    table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255);
+    table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215);
+    table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220);
+    table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255);
+    table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255);
+    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255);
+    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255);
+    table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255);
+    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255);
+    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255);
+    table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255);
+    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255);
+    table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255);
+    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245);
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255);
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255);
+    table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255);
+    table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225);
+    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255);
+    table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255);
+    table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255);
+    table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255);
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
+    table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
+    table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255);
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_DARK) {
+    table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
+    table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215);
+    table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
+    table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
+    table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);
+    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);
+    table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);
+    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);
+    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
+    table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);
+    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);
+    table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
+    table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
+    table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_DRACULA) {
+    struct nk_color background = nk_rgba(40, 42, 54, 255);
+    struct nk_color currentline = nk_rgba(68, 71, 90, 255);
+    struct nk_color foreground = nk_rgba(248, 248, 242, 255);
+    struct nk_color comment = nk_rgba(98, 114, 164, 255);
+    /* struct nk_color cyan = nk_rgba(139, 233, 253, 255); */
+    /* struct nk_color green = nk_rgba(80, 250, 123, 255); */
+    /* struct nk_color orange = nk_rgba(255, 184, 108, 255); */
+    struct nk_color pink = nk_rgba(255, 121, 198, 255);
+    struct nk_color purple = nk_rgba(189, 147, 249, 255);
+    /* struct nk_color red = nk_rgba(255, 85, 85, 255); */
+    /* struct nk_color yellow = nk_rgba(241, 250, 140, 255); */
+    table[NK_COLOR_TEXT] = foreground;
+    table[NK_COLOR_WINDOW] = background;
+    table[NK_COLOR_HEADER] = currentline;
+    table[NK_COLOR_BORDER] = currentline;
+    table[NK_COLOR_BUTTON] = currentline;
+    table[NK_COLOR_BUTTON_HOVER] = comment;
+    table[NK_COLOR_BUTTON_ACTIVE] = purple;
+    table[NK_COLOR_TOGGLE] = currentline;
+    table[NK_COLOR_TOGGLE_HOVER] = comment;
+    table[NK_COLOR_TOGGLE_CURSOR] = pink;
+    table[NK_COLOR_SELECT] = currentline;
+    table[NK_COLOR_SELECT_ACTIVE] = comment;
+    table[NK_COLOR_SLIDER] = background;
+    table[NK_COLOR_SLIDER_CURSOR] = currentline;
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = comment;
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = comment;
+    table[NK_COLOR_PROPERTY] = currentline;
+    table[NK_COLOR_EDIT] = currentline;
+    table[NK_COLOR_EDIT_CURSOR] = foreground;
+    table[NK_COLOR_COMBO] = currentline;
+    table[NK_COLOR_CHART] = currentline;
+    table[NK_COLOR_CHART_COLOR] = comment;
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = purple;
+    table[NK_COLOR_SCROLLBAR] = background;
+    table[NK_COLOR_SCROLLBAR_CURSOR] = currentline;
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = comment;
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = purple;
+    table[NK_COLOR_TAB_HEADER] = currentline;
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_CATPPUCCIN_LATTE) {
+    /*struct nk_color rosewater = nk_rgba(220, 138, 120, 255);*/
+    /*struct nk_color flamingo = nk_rgba(221, 120, 120, 255);*/
+    struct nk_color pink = nk_rgba(234, 118, 203, 255);
+    struct nk_color mauve = nk_rgba(136, 57, 239, 255);
+    /*struct nk_color red = nk_rgba(210, 15, 57, 255);*/
+    /*struct nk_color maroon = nk_rgba(230, 69, 83, 255);*/
+    /*struct nk_color peach = nk_rgba(254, 100, 11, 255);*/
+    struct nk_color yellow = nk_rgba(223, 142, 29, 255);
+    /*struct nk_color green = nk_rgba(64, 160, 43, 255);*/
+    struct nk_color teal = nk_rgba(23, 146, 153, 255);
+    /*struct nk_color sky = nk_rgba(4, 165, 229, 255);*/
+    /*struct nk_color sapphire = nk_rgba(32, 159, 181, 255);*/
+    /*struct nk_color blue = nk_rgba(30, 102, 245, 255);*/
+    /*struct nk_color lavender = nk_rgba(114, 135, 253, 255);*/
+    struct nk_color text = nk_rgba(76, 79, 105, 255);
+    /*struct nk_color subtext1 = nk_rgba(92, 95, 119, 255);*/
+    /*struct nk_color subtext0 = nk_rgba(108, 111, 133, 255);*/
+    struct nk_color overlay2 = nk_rgba(124, 127, 147, 55);
+    /*struct nk_color overlay1 = nk_rgba(140, 143, 161, 255);*/
+    struct nk_color overlay0 = nk_rgba(156, 160, 176, 255);
+    struct nk_color surface2 = nk_rgba(172, 176, 190, 255);
+    struct nk_color surface1 = nk_rgba(188, 192, 204, 255);
+    struct nk_color surface0 = nk_rgba(204, 208, 218, 255);
+    struct nk_color base = nk_rgba(239, 241, 245, 255);
+    struct nk_color mantle = nk_rgba(230, 233, 239, 255);
+    /*struct nk_color crust = nk_rgba(220, 224, 232, 255);*/
+    table[NK_COLOR_TEXT] = text;
+    table[NK_COLOR_WINDOW] = base;
+    table[NK_COLOR_HEADER] = mantle;
+    table[NK_COLOR_BORDER] = mantle;
+    table[NK_COLOR_BUTTON] = surface0;
+    table[NK_COLOR_BUTTON_HOVER] = overlay2;
+    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;
+    table[NK_COLOR_TOGGLE] = surface2;
+    table[NK_COLOR_TOGGLE_HOVER] = overlay2;
+    table[NK_COLOR_TOGGLE_CURSOR] = yellow;
+    table[NK_COLOR_SELECT] = surface0;
+    table[NK_COLOR_SELECT_ACTIVE] = overlay0;
+    table[NK_COLOR_SLIDER] = surface1;
+    table[NK_COLOR_SLIDER_CURSOR] = teal;
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = teal;
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = teal;
+    table[NK_COLOR_PROPERTY] = surface0;
+    table[NK_COLOR_EDIT] = surface0;
+    table[NK_COLOR_EDIT_CURSOR] = mauve;
+    table[NK_COLOR_COMBO] = surface0;
+    table[NK_COLOR_CHART] = surface0;
+    table[NK_COLOR_CHART_COLOR] = teal;
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = mauve;
+    table[NK_COLOR_SCROLLBAR] = surface0;
+    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = mauve;
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = mauve;
+    table[NK_COLOR_TAB_HEADER] = surface0;
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = pink;
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_CATPPUCCIN_FRAPPE) {
+    /*struct nk_color rosewater = nk_rgba(242, 213, 207, 255);*/
+    /*struct nk_color flamingo = nk_rgba(238, 190, 190, 255);*/
+    struct nk_color pink = nk_rgba(244, 184, 228, 255);
+    /*struct nk_color mauve = nk_rgba(202, 158, 230, 255);*/
+    /*struct nk_color red = nk_rgba(231, 130, 132, 255);*/
+    /*struct nk_color maroon = nk_rgba(234, 153, 156, 255);*/
+    /*struct nk_color peach = nk_rgba(239, 159, 118, 255);*/
+    /*struct nk_color yellow = nk_rgba(229, 200, 144, 255);*/
+    struct nk_color green = nk_rgba(166, 209, 137, 255);
+    /*struct nk_color teal = nk_rgba(129, 200, 190, 255);*/
+    /*struct nk_color sky = nk_rgba(153, 209, 219, 255);*/
+    /*struct nk_color sapphire = nk_rgba(133, 193, 220, 255);*/
+    /*struct nk_color blue = nk_rgba(140, 170, 238, 255);*/
+    struct nk_color lavender = nk_rgba(186, 187, 241, 255);
+    struct nk_color text = nk_rgba(198, 208, 245, 255);
+    /*struct nk_color subtext1 = nk_rgba(181, 191, 226, 255);*/
+    /*struct nk_color subtext0 = nk_rgba(165, 173, 206, 255);*/
+    struct nk_color overlay2 = nk_rgba(148, 156, 187, 255);
+    struct nk_color overlay1 = nk_rgba(131, 139, 167, 255);
+    struct nk_color overlay0 = nk_rgba(115, 121, 148, 255);
+    struct nk_color surface2 = nk_rgba(98, 104, 128, 255);
+    struct nk_color surface1 = nk_rgba(81, 87, 109, 255);
+    struct nk_color surface0 = nk_rgba(65, 69, 89, 255);
+    struct nk_color base = nk_rgba(48, 52, 70, 255);
+    struct nk_color mantle = nk_rgba(41, 44, 60, 255);
+    /*struct nk_color crust = nk_rgba(35, 38, 52, 255);*/
+    table[NK_COLOR_TEXT] = text;
+    table[NK_COLOR_WINDOW] = base;
+    table[NK_COLOR_HEADER] = mantle;
+    table[NK_COLOR_BORDER] = mantle;
+    table[NK_COLOR_BUTTON] = surface0;
+    table[NK_COLOR_BUTTON_HOVER] = overlay1;
+    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;
+    table[NK_COLOR_TOGGLE] = surface2;
+    table[NK_COLOR_TOGGLE_HOVER] = overlay2;
+    table[NK_COLOR_TOGGLE_CURSOR] = pink;
+    table[NK_COLOR_SELECT] = surface0;
+    table[NK_COLOR_SELECT_ACTIVE] = overlay0;
+    table[NK_COLOR_SLIDER] = surface1;
+    table[NK_COLOR_SLIDER_CURSOR] = green;
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;
+    table[NK_COLOR_PROPERTY] = surface0;
+    table[NK_COLOR_EDIT] = surface0;
+    table[NK_COLOR_EDIT_CURSOR] = pink;
+    table[NK_COLOR_COMBO] = surface0;
+    table[NK_COLOR_CHART] = surface0;
+    table[NK_COLOR_CHART_COLOR] = lavender;
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = pink;
+    table[NK_COLOR_SCROLLBAR] = surface0;
+    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = lavender;
+    table[NK_COLOR_TAB_HEADER] = surface0;
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = pink;
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;
+    nk_style_from_table(ctx, table);
+  } else if (theme == THEME_CATPPUCCIN_MACCHIATO) {
+    /*struct nk_color rosewater = nk_rgba(244, 219, 214, 255);*/
+    /*struct nk_color flamingo = nk_rgba(240, 198, 198, 255);*/
+    struct nk_color pink = nk_rgba(245, 189, 230, 255);
+    /*struct nk_color mauve = nk_rgba(198, 160, 246, 255);*/
+    /*struct nk_color red = nk_rgba(237, 135, 150, 255);*/
+    /*struct nk_color maroon = nk_rgba(238, 153, 160, 255);*/
+    /*struct nk_color peach = nk_rgba(245, 169, 127, 255);*/
+    struct nk_color yellow = nk_rgba(238, 212, 159, 255);
+    struct nk_color green = nk_rgba(166, 218, 149, 255);
+    /*struct nk_color teal = nk_rgba(139, 213, 202, 255);*/
+    /*struct nk_color sky = nk_rgba(145, 215, 227, 255);*/
+    /*struct nk_color sapphire = nk_rgba(125, 196, 228, 255);*/
+    /*struct nk_color blue = nk_rgba(138, 173, 244, 255);*/
+    struct nk_color lavender = nk_rgba(183, 189, 248, 255);
+    struct nk_color text = nk_rgba(202, 211, 245, 255);
+    /*struct nk_color subtext1 = nk_rgba(184, 192, 224, 255);*/
+    /*struct nk_color subtext0 = nk_rgba(165, 173, 203, 255);*/
+    struct nk_color overlay2 = nk_rgba(147, 154, 183, 255);
+    struct nk_color overlay1 = nk_rgba(128, 135, 162, 255);
+    struct nk_color overlay0 = nk_rgba(110, 115, 141, 255);
+    struct nk_color surface2 = nk_rgba(91, 96, 120, 255);
+    struct nk_color surface1 = nk_rgba(73, 77, 100, 255);
+    struct nk_color surface0 = nk_rgba(54, 58, 79, 255);
+    struct nk_color base = nk_rgba(36, 39, 58, 255);
+    struct nk_color mantle = nk_rgba(30, 32, 48, 255);
+    /*struct nk_color crust = nk_rgba(24, 25, 38, 255);*/
+    table[NK_COLOR_TEXT] = text;
+    table[NK_COLOR_WINDOW] = base;
+    table[NK_COLOR_HEADER] = mantle;
+    table[NK_COLOR_BORDER] = mantle;
+    table[NK_COLOR_BUTTON] = surface0;
+    table[NK_COLOR_BUTTON_HOVER] = overlay1;
+    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;
+    table[NK_COLOR_TOGGLE] = surface2;
+    table[NK_COLOR_TOGGLE_HOVER] = overlay2;
+    table[NK_COLOR_TOGGLE_CURSOR] = yellow;
+    table[NK_COLOR_SELECT] = surface0;
+    table[NK_COLOR_SELECT_ACTIVE] = overlay0;
+    table[NK_COLOR_SLIDER] = surface1;
+    table[NK_COLOR_SLIDER_CURSOR] = green;
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;
+    table[NK_COLOR_PROPERTY] = surface0;
+    table[NK_COLOR_EDIT] = surface0;
+    table[NK_COLOR_EDIT_CURSOR] = pink;
+    table[NK_COLOR_COMBO] = surface0;
+    table[NK_COLOR_CHART] = surface0;
+    table[NK_COLOR_CHART_COLOR] = lavender;
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = yellow;
+    table[NK_COLOR_SCROLLBAR] = surface0;
+    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = lavender;
+    table[NK_COLOR_TAB_HEADER] = surface0;
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = pink;
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;
+    nk_style_from_table(ctx, table); 
+  } else if (theme == THEME_CATPPUCCIN_MOCHA) {
+    /*struct nk_color rosewater = nk_rgba(245, 224, 220, 255);*/
+    /*struct nk_color flamingo = nk_rgba(242, 205, 205, 255);*/
+    struct nk_color pink = nk_rgba(245, 194, 231, 255);
+    /*struct nk_color mauve = nk_rgba(203, 166, 247, 255);*/
+    /*struct nk_color red = nk_rgba(243, 139, 168, 255);*/
+    /*struct nk_color maroon = nk_rgba(235, 160, 172, 255);*/
+    /*struct nk_color peach = nk_rgba(250, 179, 135, 255);*/
+    /*struct nk_color yellow = nk_rgba(249, 226, 175, 255);*/
+    struct nk_color green = nk_rgba(166, 227, 161, 255);
+    /*struct nk_color teal = nk_rgba(148, 226, 213, 255);*/
+    /*struct nk_color sky = nk_rgba(137, 220, 235, 255);*/
+    /*struct nk_color sapphire = nk_rgba(116, 199, 236, 255);*/
+    /*struct nk_color blue = nk_rgba(137, 180, 250, 255);*/
+    struct nk_color lavender = nk_rgba(180, 190, 254, 255);
+    struct nk_color text = nk_rgba(205, 214, 244, 255);
+    /*struct nk_color subtext1 = nk_rgba(186, 194, 222, 255);*/
+    /*struct nk_color subtext0 = nk_rgba(166, 173, 200, 255);*/
+    struct nk_color overlay2 = nk_rgba(147, 153, 178, 255);
+    struct nk_color overlay1 = nk_rgba(127, 132, 156, 255);
+    struct nk_color overlay0 = nk_rgba(108, 112, 134, 255);
+    struct nk_color surface2 = nk_rgba(88, 91, 112, 255);
+    struct nk_color surface1 = nk_rgba(69, 71, 90, 255);
+    struct nk_color surface0 = nk_rgba(49, 50, 68, 255);
+    struct nk_color base = nk_rgba(30, 30, 46, 255);
+    struct nk_color mantle = nk_rgba(24, 24, 37, 255);
+    /*struct nk_color crust = nk_rgba(17, 17, 27, 255);*/
+    table[NK_COLOR_TEXT] = text;
+    table[NK_COLOR_WINDOW] = base;
+    table[NK_COLOR_HEADER] = mantle;
+    table[NK_COLOR_BORDER] = mantle;
+    table[NK_COLOR_BUTTON] = surface0;
+    table[NK_COLOR_BUTTON_HOVER] = overlay1;
+    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;
+    table[NK_COLOR_TOGGLE] = surface2;
+    table[NK_COLOR_TOGGLE_HOVER] = overlay2;
+    table[NK_COLOR_TOGGLE_CURSOR] = lavender;
+    table[NK_COLOR_SELECT] = surface0;
+    table[NK_COLOR_SELECT_ACTIVE] = overlay0;
+    table[NK_COLOR_SLIDER] = surface1;
+    table[NK_COLOR_SLIDER_CURSOR] = green;
+    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;
+    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;
+    table[NK_COLOR_PROPERTY] = surface0;
+    table[NK_COLOR_EDIT] = surface0;
+    table[NK_COLOR_EDIT_CURSOR] = lavender;
+    table[NK_COLOR_COMBO] = surface0;
+    table[NK_COLOR_CHART] = surface0;
+    table[NK_COLOR_CHART_COLOR] = lavender;
+    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = pink;
+    table[NK_COLOR_SCROLLBAR] = surface0;
+    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;
+    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;
+    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = pink;
+    table[NK_COLOR_TAB_HEADER] = surface0;
+    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];
+    table[NK_COLOR_KNOB_CURSOR] = pink;
+    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;
+    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;
+    nk_style_from_table(ctx, table);   
+  } else {
+    nk_style_default(ctx);
+  }
 }
-
-

+ 1 - 1
demo/d3d11/main.c

@@ -37,7 +37,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 22 - 0
demo/d3d11/nuklear_d3d11.h

@@ -239,6 +239,14 @@ nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
             nk_input_key(&d3d11.ctx, NK_KEY_TAB, down);
             return 1;
 
+        case VK_UP:
+            nk_input_key(&d3d11.ctx, NK_KEY_UP, down);
+            return 1;
+
+        case VK_DOWN:
+            nk_input_key(&d3d11.ctx, NK_KEY_DOWN, down);
+            return 1;
+
         case VK_LEFT:
             if (ctrl)
                 nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down);
@@ -275,6 +283,20 @@ nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
             nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down);
             return 1;
 
+        case 'B':
+            if (ctrl) {
+                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_LINE_START, down);
+                return 1;
+            }
+            break;
+
+        case 'E':
+            if (ctrl) {
+                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_LINE_END, down);
+                return 1;
+            }
+            break;
+
         case 'C':
             if (ctrl) {
                 nk_input_key(&d3d11.ctx, NK_KEY_COPY, down);

+ 1 - 1
demo/d3d12/main.c

@@ -40,7 +40,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/d3d9/main.c

@@ -34,7 +34,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/gdi/main.c

@@ -29,7 +29,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/gdip/main.c

@@ -29,7 +29,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/glfw_opengl3/main.c

@@ -42,7 +42,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/glfw_opengl4/main.c

@@ -42,7 +42,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 39 - 8
demo/glfw_vulkan/main.c

@@ -139,8 +139,19 @@ struct vulkan_demo {
     VkDeviceMemory demo_texture_memory;
 
     VkFence render_fence;
+
+    bool framebuffer_resized;
 };
 
+static void glfw_framebuffer_resize_callback(GLFWwindow* window, int width, int height) {
+    struct vulkan_demo* demo;
+
+    (void)width;
+    (void)height;
+    demo = glfwGetWindowUserPointer(window);
+    demo->framebuffer_resized = true;
+}
+
 static void glfw_error_callback(int e, const char *d) {
     fprintf(stderr, "Error %d: %s\n", e, d);
 }
@@ -299,7 +310,7 @@ bool create_instance(struct vulkan_demo *demo) {
         if (i > 0) {
             printf(", ");
         }
-        printf(enabled_extensions[i]);
+        printf("%s\n", enabled_extensions[i]);
     }
     printf("\n");
     for (i = 0; i < enabled_extension_count; i++) {
@@ -1227,8 +1238,8 @@ bool create_graphics_pipeline(struct vulkan_demo *demo) {
     bool ret = false;
     char *vert_shader_code = NULL;
     char *frag_shader_code = NULL;
-    VkShaderModule vert_shader_module;
-    VkShaderModule frag_shader_module;
+    VkShaderModule vert_shader_module = VK_NULL_HANDLE;
+    VkShaderModule frag_shader_module = VK_NULL_HANDLE;
     FILE *fp;
     size_t file_len;
     VkPipelineShaderStageCreateInfo vert_shader_stage_info;
@@ -1246,8 +1257,9 @@ bool create_graphics_pipeline(struct vulkan_demo *demo) {
     VkPipelineLayoutCreateInfo pipeline_layout_info;
     VkResult result;
     VkGraphicsPipelineCreateInfo pipeline_info;
+    size_t read_result;
 
-    fp = fopen("shaders/demo.vert.spv", "r");
+    fp = fopen("shaders/demo.vert.spv", "rb");
     if (!fp) {
         fprintf(stderr, "Couldn't open shaders/demo.vert.spv\n");
         return false;
@@ -1256,15 +1268,19 @@ bool create_graphics_pipeline(struct vulkan_demo *demo) {
     file_len = ftell(fp);
     vert_shader_code = malloc(file_len);
     fseek(fp, 0, 0);
-    fread(vert_shader_code, 1, file_len, fp);
+    read_result = fread(vert_shader_code, file_len, 1, fp);
     fclose(fp);
+    if (read_result != 1) {
+        fprintf(stderr, "Could not read fragment shader\n");
+        goto cleanup;
+    }
 
     if (!create_shader_module(demo->device, vert_shader_code, file_len,
                               &vert_shader_module)) {
         goto cleanup;
     }
 
-    fp = fopen("shaders/demo.frag.spv", "r");
+    fp = fopen("shaders/demo.frag.spv", "rb");
     if (!fp) {
         fprintf(stderr, "Couldn't open shaders/demo.frag.spv\n");
         return false;
@@ -1273,8 +1289,12 @@ bool create_graphics_pipeline(struct vulkan_demo *demo) {
     file_len = ftell(fp);
     frag_shader_code = malloc(file_len);
     fseek(fp, 0, 0);
-    fread(frag_shader_code, 1, file_len, fp);
+    read_result = fread(frag_shader_code, file_len, 1, fp);
     fclose(fp);
+    if (read_result != 1) {
+        fprintf(stderr, "Could not read fragment shader\n");
+        goto cleanup;
+    }
 
     if (!create_shader_module(demo->device, frag_shader_code, file_len,
                               &frag_shader_module)) {
@@ -1862,6 +1882,8 @@ bool create_vulkan_demo(struct vulkan_demo *demo) {
         return false;
     }
 
+    demo->framebuffer_resized = false;
+
     return true;
 }
 
@@ -1876,6 +1898,9 @@ bool recreate_swap_chain(struct vulkan_demo *demo) {
     update_descriptor_sets(demo);
     nk_glfw3_resize(demo->swap_chain_image_extent.width,
                     demo->swap_chain_image_extent.height);
+
+    demo->framebuffer_resized = false;
+
     return true;
 }
 
@@ -1961,7 +1986,7 @@ bool render(struct vulkan_demo *demo, struct nk_colorf *bg,
 
     result = vkQueuePresentKHR(demo->present_queue, &present_info);
 
-    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
+    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || demo->framebuffer_resized) {
         recreate_swap_chain(demo);
     } else if (result != VK_SUCCESS) {
         fprintf(stderr, "vkQueuePresentKHR failed: %d\n", result);
@@ -2073,6 +2098,8 @@ int main(void) {
     memset(&demo, 0, sizeof(struct vulkan_demo));
     demo.win =
         glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwSetWindowUserPointer(demo.win, &demo);
+    glfwSetFramebufferSizeCallback(demo.win, glfw_framebuffer_resize_callback);
 
     if (!create_vulkan_demo(&demo)) {
         fprintf(stderr, "failed to create vulkan demo!\n");
@@ -2192,6 +2219,10 @@ int main(void) {
                                   demo.image_available, NULL, &image_index);
 
         if (result == VK_ERROR_OUT_OF_DATE_KHR) {
+            recreate_swap_chain(&demo);
+
+            /* If vkAcquireNextImageKHR does not successfully acquire an image,
+             * semaphore and fence are unaffected. */
             continue;
         }
         if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {

+ 2 - 5
demo/glfw_vulkan/nuklear_glfw_vulkan.h

@@ -372,7 +372,6 @@ static struct nk_glfw {
     struct nk_glfw_device vulkan;
     struct nk_context ctx;
     struct nk_font_atlas atlas;
-    struct nk_vec2 fb_scale;
     unsigned int text[NK_GLFW_TEXT_MAX];
     int text_len;
     struct nk_vec2 scroll;
@@ -1179,8 +1178,6 @@ NK_API void nk_glfw3_resize(uint32_t framebuffer_width,
     struct nk_glfw_device *dev = &glfw.vulkan;
     glfwGetWindowSize(glfw.win, &glfw.width, &glfw.height);
     glfwGetFramebufferSize(glfw.win, &glfw.display_width, &glfw.display_height);
-    glfw.fb_scale.x = (float)glfw.display_width / (float)glfw.width;
-    glfw.fb_scale.y = (float)glfw.display_height / (float)glfw.height;
 
     nk_glfw3_destroy_render_resources(dev);
     nk_glfw3_create_render_resources(dev, framebuffer_width,
@@ -1264,7 +1261,7 @@ NK_API void nk_glfw3_new_frame(void) {
     for (i = 0; i < glfw.text_len; ++i)
         nk_input_unicode(ctx, glfw.text[i]);
 
-#ifdef NK_GLFW_GL4_MOUSE_GRABBING
+#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING
     /* optional grabbing behavior */
     if (ctx->input.mouse.grab)
         glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
@@ -1332,7 +1329,7 @@ NK_API void nk_glfw3_new_frame(void) {
 
     glfwGetCursorPos(win, &x, &y);
     nk_input_motion(ctx, (int)x, (int)y);
-#ifdef NK_GLFW_GL4_MOUSE_GRABBING
+#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING
     if (ctx->input.mouse.grabbed) {
         glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x,
                          ctx->input.mouse.prev.y);

+ 9 - 6
demo/glfw_vulkan/src/nuklear_glfw_vulkan.in.h

@@ -24,6 +24,7 @@ unsigned char nuklearshaders_nuklear_frag_spv[] = {};
 unsigned int nuklearshaders_nuklear_frag_spv_len = 0;
 // NUKLEAR_SHADERS_END
 
+#include <assert.h>
 #include <stddef.h>
 #include <string.h>
 #define GLFW_INCLUDE_VULKAN
@@ -71,7 +72,6 @@ NK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button,
  */
 #ifdef NK_GLFW_VULKAN_IMPLEMENTATION
 #undef NK_GLFW_VULKAN_IMPLEMENTATION
-#include <assert.h>
 #include <stdlib.h>
 
 #ifndef NK_GLFW_TEXT_MAX
@@ -149,13 +149,13 @@ static struct nk_glfw {
     struct nk_glfw_device vulkan;
     struct nk_context ctx;
     struct nk_font_atlas atlas;
-    struct nk_vec2 fb_scale;
     unsigned int text[NK_GLFW_TEXT_MAX];
     int text_len;
     struct nk_vec2 scroll;
     double last_button_click;
     int is_double_click_down;
     struct nk_vec2 double_click_pos;
+    float delta_time_seconds_last;
 } glfw;
 
 struct Mat4f {
@@ -955,8 +955,6 @@ NK_API void nk_glfw3_resize(uint32_t framebuffer_width,
     struct nk_glfw_device *dev = &glfw.vulkan;
     glfwGetWindowSize(glfw.win, &glfw.width, &glfw.height);
     glfwGetFramebufferSize(glfw.win, &glfw.display_width, &glfw.display_height);
-    glfw.fb_scale.x = (float)glfw.display_width / (float)glfw.width;
-    glfw.fb_scale.y = (float)glfw.display_height / (float)glfw.height;
 
     nk_glfw3_destroy_render_resources(dev);
     nk_glfw3_create_render_resources(dev, framebuffer_width,
@@ -1031,11 +1029,16 @@ NK_API void nk_glfw3_new_frame(void) {
     struct nk_context *ctx = &glfw.ctx;
     struct GLFWwindow *win = glfw.win;
 
+    /* update the timer */
+    float delta_time_now = (float)glfwGetTime();
+    glfw.ctx.delta_time_seconds = delta_time_now - glfw.delta_time_seconds_last;
+    glfw.delta_time_seconds_last = delta_time_now;
+
     nk_input_begin(ctx);
     for (i = 0; i < glfw.text_len; ++i)
         nk_input_unicode(ctx, glfw.text[i]);
 
-#ifdef NK_GLFW_GL4_MOUSE_GRABBING
+#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING
     /* optional grabbing behavior */
     if (ctx->input.mouse.grab)
         glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
@@ -1103,7 +1106,7 @@ NK_API void nk_glfw3_new_frame(void) {
 
     glfwGetCursorPos(win, &x, &y);
     nk_input_motion(ctx, (int)x, (int)y);
-#ifdef NK_GLFW_GL4_MOUSE_GRABBING
+#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING
     if (ctx->input.mouse.grabbed) {
         glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x,
                          ctx->input.mouse.prev.y);

+ 1 - 1
demo/rawfb/sdl/main.c

@@ -33,7 +33,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/rawfb/wayland/main.c

@@ -62,7 +62,7 @@ struct nk_wayland {
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/rawfb/x11/Makefile

@@ -1,5 +1,5 @@
 # Install
-BIN = zahnrad
+BIN = demo
 
 # Flags
 CFLAGS += -std=c89 -Wall -Wextra -pedantic -Wno-unused-function

+ 1 - 1
demo/rawfb/x11/main.c

@@ -114,7 +114,7 @@ sleep_for(long t)
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/sdl_opengl2/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Flags
-CFLAGS += -std=c89 -Wall -Wextra -pedantic
+CFLAGS += -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H
 
 SRC = main.c
 OBJ = $(SRC:.c=.o)

+ 2 - 2
demo/sdl_opengl2/main.c

@@ -34,11 +34,11 @@
  * ===============================================================*/
 /* 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_ALL 
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/sdl_opengl3/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Flags
-CFLAGS += -std=c89 -Wall -Wextra -pedantic
+CFLAGS += -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H
 
 SRC = main.c
 OBJ = $(SRC:.c=.o)

+ 1 - 1
demo/sdl_opengl3/main.c

@@ -42,7 +42,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/sdl_opengles2/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Flags
-CFLAGS += -std=c89 -Wall -Wextra -pedantic
+CFLAGS += -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H
 
 SRC = main.c
 OBJ = $(SRC:.c=.o)

+ 1 - 1
demo/sdl_opengles2/main.c

@@ -43,7 +43,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/sdl_renderer/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Flags
-CFLAGS += -std=c89 -pedantic -O0
+CFLAGS += -std=c89 -Wall -Wextra -pedantic -O2 -DSDL_DISABLE_IMMINTRIN_H
 CFLAGS += `sdl2-config --cflags`
 
 SRC = main.c

+ 1 - 1
demo/sdl_renderer/main.c

@@ -37,7 +37,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 3 - 0
demo/sdl_vulkan/.gitignore

@@ -0,0 +1,3 @@
+src/nuklearshaders/*.spv
+src/nuklear_sdl_vulkan.h
+shaders/*.spv

+ 30 - 0
demo/sdl_vulkan/Makefile

@@ -0,0 +1,30 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS += -std=c89 -Wall -Wextra -pedantic -fsanitize=address -O2
+CFLAGS += -DSDL_DISABLE_IMMINTRIN_H
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lsdl2 -lvulkan -lm
+else
+	UNAME_S := $(shell uname -s)
+	SDL2 := $(shell pkg-config --libs sdl2)
+	LIBS = $(SDL2) -lvulkan -lm
+endif
+
+
+$(BIN): shaders/demo.vert.spv shaders/demo.frag.spv
+	@mkdir -p bin
+	rm -f bin/$(BIN) $(OBJS)
+	$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
+
+shaders/demo.vert.spv: shaders/demo.vert
+	glslc --target-env=vulkan shaders/demo.vert -o shaders/demo.vert.spv
+
+shaders/demo.frag.spv: shaders/demo.frag
+	glslc --target-env=vulkan shaders/demo.frag -o shaders/demo.frag.spv

+ 52 - 0
demo/sdl_vulkan/README.md

@@ -0,0 +1,52 @@
+# nuklear sdl vulkan
+
+## Theory of operation
+
+The nuklear SDL vulkan integration creates an independent graphics pipeline that will render the nuklear UI to separate render targets.
+The application is responsible to fully manage these render targets. So it must ensure they are properly sized (and resized when requested).
+
+Furthermore it is assumed that you will have a swap chain in place and the number of nuklear overlay images and number of swap chain images match.
+
+This is how you can integrate it in your application:
+
+```
+/*
+Setup: overlay_images have been created and their number match with the number
+of the swap_chain_images of your application. The overlay_images in this
+example have the same format as your swap_chain images (optional)
+*/
+    struct nk_context *ctx = nk_sdl_init(
+        demo.win, demo.device, demo.physical_device, demo.indices.graphics,
+        demo.overlay_image_views, demo.swap_chain_images_len,
+        demo.swap_chain_image_format, 0,
+        MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+[...]
+/*
+in your draw loop draw you can then render to the overlay image at
+`image_index`
+your own application can then wait for the semaphore and produce
+the swap_chain_image at `image_index`
+this should simply sample from the overlay_image (see example)
+*/
+nk_semaphore semaphore =
+    nk_sdl_render(demo.graphics_queue, image_index,
+                    demo.image_available, NK_ANTI_ALIASING_ON);
+    if (!render(&demo, &bg, nk_semaphore, image_index)) {
+        fprintf(stderr, "render failed\n");
+        return false;
+    }
+```
+
+You must call `nk_sdl_resize` whenever the size of the overlay_images resize.
+
+## Using images
+
+Images can be used by providing a VkImageView as an nk_image_ptr to nuklear:
+
+```
+img = nk_image_ptr(demo.demo_texture_image_view);
+```
+
+Note that they must have SHADER_READ_OPTIMAL layout
+
+It is currently not possible to specify how they are being sampled. The nuklear SDL vulkan integration uses a fixed sampler that does linear filtering.

+ 2251 - 0
demo/sdl_vulkan/main.c

@@ -0,0 +1,2251 @@
+/* nuklear - 1.32.0 - public domain */
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+#include <vulkan/vulkan.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_VULKAN_IMPLEMENTATION
+#define NK_KEYSTATE_BASED_INPUT
+#include "../../nuklear.h"
+#include "nuklear_sdl_vulkan.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+/* ===============================================================
+ *
+ *                          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_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+#define INCLUDE_STYLE
+#define INCLUDE_CALCULATOR
+#define INCLUDE_CANVAS
+#define INCLUDE_OVERVIEW
+#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_NODE_EDITOR
+#include "../../demo/common/node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+
+static const char *validation_layer_name = "VK_LAYER_KHRONOS_validation";
+
+struct queue_family_indices {
+    int graphics;
+    int present;
+};
+
+struct swap_chain_support_details {
+    VkSurfaceCapabilitiesKHR capabilities;
+    VkSurfaceFormatKHR *formats;
+    uint32_t formats_len;
+    VkPresentModeKHR *present_modes;
+    uint32_t present_modes_len;
+};
+
+void swap_chain_support_details_free(
+    struct swap_chain_support_details *swap_chain_support) {
+    if (swap_chain_support->formats_len > 0) {
+        free(swap_chain_support->formats);
+        swap_chain_support->formats = NULL;
+    }
+    if (swap_chain_support->present_modes_len > 0) {
+        free(swap_chain_support->present_modes);
+        swap_chain_support->present_modes = NULL;
+    }
+}
+
+struct vulkan_demo {
+    SDL_Window *win;
+    VkInstance instance;
+    VkDebugUtilsMessengerEXT debug_messenger;
+    VkSurfaceKHR surface;
+    VkPhysicalDevice physical_device;
+    struct queue_family_indices indices;
+    VkDevice device;
+    VkQueue graphics_queue;
+    VkQueue present_queue;
+    VkSampler sampler;
+
+    VkSwapchainKHR swap_chain;
+    VkImage *swap_chain_images;
+    uint32_t swap_chain_images_len;
+    VkImageView *swap_chain_image_views;
+    VkFormat swap_chain_image_format;
+    VkExtent2D swap_chain_image_extent;
+
+    VkImage *overlay_images;
+    VkImageView *overlay_image_views;
+    VkDeviceMemory *overlay_image_memories;
+
+    VkRenderPass render_pass;
+    VkFramebuffer *framebuffers;
+    VkDescriptorSetLayout descriptor_set_layout;
+    VkDescriptorPool descriptor_pool;
+    VkDescriptorSet *descriptor_sets;
+    VkPipelineLayout pipeline_layout;
+    VkPipeline pipeline;
+    VkCommandPool command_pool;
+    VkCommandBuffer *command_buffers;
+    VkSemaphore image_available;
+    VkSemaphore render_finished;
+
+    VkImage demo_texture_image;
+    VkImageView demo_texture_image_view;
+    VkDeviceMemory demo_texture_memory;
+
+    VkFence render_fence;
+};
+
+VKAPI_ATTR VkBool32 VKAPI_CALL
+vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
+                      VkDebugUtilsMessageTypeFlagsEXT message_type,
+                      const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
+                      void *user_data) {
+    (void)message_severity;
+    (void)message_type;
+    (void)user_data;
+    fprintf(stderr, "validation layer: %s\n", callback_data->pMessage);
+
+    return VK_FALSE;
+}
+
+bool check_validation_layer_support() {
+    uint32_t layer_count;
+    bool ret = false;
+    VkResult result;
+    uint32_t i;
+    VkLayerProperties *available_layers = NULL;
+
+    result = vkEnumerateInstanceLayerProperties(&layer_count, NULL);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateInstanceLayerProperties failed: %d\n",
+                result);
+        return ret;
+    }
+
+    available_layers = malloc(layer_count * sizeof(VkLayerProperties));
+    result = vkEnumerateInstanceLayerProperties(&layer_count, available_layers);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateInstanceLayerProperties failed: %d\n",
+                result);
+        goto cleanup;
+    }
+
+    printf("Available vulkan layers:\n");
+    for (i = 0; i < layer_count; i++) {
+        printf("  %s\n", available_layers[i].layerName);
+        if (strcmp(validation_layer_name, available_layers[i].layerName) == 0) {
+            ret = true;
+            break;
+        }
+    }
+cleanup:
+    free(available_layers);
+    return ret;
+}
+
+VkResult create_debug_utils_messenger_ext(
+    VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
+    const VkAllocationCallbacks *pAllocator,
+    VkDebugUtilsMessengerEXT *pDebugMessenger) {
+    PFN_vkCreateDebugUtilsMessengerEXT func =
+        (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
+            instance, "vkCreateDebugUtilsMessengerEXT");
+    if (func != NULL) {
+        return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
+    } else {
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+}
+
+bool create_debug_callback(struct vulkan_demo *demo) {
+    VkResult result;
+
+    VkDebugUtilsMessengerCreateInfoEXT create_info;
+    memset(&create_info, 0, sizeof(VkDebugUtilsMessengerCreateInfoEXT));
+    create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+    create_info.messageSeverity =
+        VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
+        VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+    create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
+                              VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
+                              VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+    create_info.pfnUserCallback = vulkan_debug_callback;
+
+    result = create_debug_utils_messenger_ext(demo->instance, &create_info,
+                                              NULL, &demo->debug_messenger);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "create_debug_utils_messenger_ext failed %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_instance(struct vulkan_demo *demo) {
+    uint32_t i;
+    uint32_t available_instance_extension_count;
+    VkResult result;
+    VkExtensionProperties *available_instance_extensions = NULL;
+    bool ret = false;
+    VkApplicationInfo app_info;
+    VkInstanceCreateInfo create_info;
+    uint32_t sdl_extension_count;
+    uint32_t enabled_extension_count;
+    const char **enabled_extensions = NULL;
+    bool validation_layers_installed;
+
+    validation_layers_installed = check_validation_layer_support();
+
+    if (!validation_layers_installed) {
+        fprintf(stdout,
+                "Couldn't find validation layer %s. Continuing without "
+                "validation layers.\n",
+                validation_layer_name);
+    }
+    result = vkEnumerateInstanceExtensionProperties(
+        NULL, &available_instance_extension_count, NULL);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateInstanceExtensionProperties failed %d\n",
+                result);
+        return ret;
+    }
+
+    available_instance_extensions = malloc(available_instance_extension_count *
+                                           sizeof(VkExtensionProperties));
+
+    result = vkEnumerateInstanceExtensionProperties(
+        NULL, &available_instance_extension_count,
+        available_instance_extensions);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateInstanceExtensionProperties failed %d\n",
+                result);
+        goto cleanup;
+    }
+
+    printf("available instance extensions:\n");
+    for (i = 0; i < available_instance_extension_count; i++) {
+        printf("  %s\n", available_instance_extensions[i].extensionName);
+    }
+
+    if (SDL_Vulkan_GetInstanceExtensions(demo->win, &sdl_extension_count,
+                                         NULL) != SDL_TRUE) {
+        fprintf(stderr, "SDL_Vulkan_GetInstanceExtensions failed: %s\n",
+                SDL_GetError());
+        goto cleanup;
+    }
+
+    enabled_extension_count =
+        sdl_extension_count + (validation_layers_installed ? 1 : 0);
+
+    enabled_extensions = malloc(enabled_extension_count * sizeof(char *));
+    if (SDL_Vulkan_GetInstanceExtensions(demo->win, &sdl_extension_count,
+                                         enabled_extensions) != SDL_TRUE) {
+        fprintf(stderr, "SDL_Vulkan_GetInstanceExtensions failed: %s\n",
+                SDL_GetError());
+        goto cleanup;
+    }
+
+    if (validation_layers_installed) {
+        enabled_extensions[sdl_extension_count] =
+            VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
+    }
+
+    printf("Trying to enable the following instance extensions: ");
+    for (i = 0; i < enabled_extension_count; i++) {
+        if (i > 0) {
+            printf(", ");
+        }
+        printf("%s\n", enabled_extensions[i]);
+    }
+    printf("\n");
+    for (i = 0; i < enabled_extension_count; i++) {
+        int extension_missing = 1;
+        uint32_t j;
+        for (j = 0; j < available_instance_extension_count; j++) {
+            if (strcmp(enabled_extensions[i],
+                       available_instance_extensions[j].extensionName) == 0) {
+                extension_missing = 0;
+                break;
+            }
+        }
+        if (extension_missing) {
+            fprintf(stderr, "Extension %s is missing\n", enabled_extensions[i]);
+            return ret;
+        }
+    }
+
+    memset(&app_info, 0, sizeof(VkApplicationInfo));
+    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    app_info.pApplicationName = "Demo";
+    app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+    app_info.pEngineName = "No Engine";
+    app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+    app_info.apiVersion = VK_API_VERSION_1_0;
+
+    memset(&create_info, 0, sizeof(VkInstanceCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    create_info.pApplicationInfo = &app_info;
+    create_info.enabledExtensionCount = enabled_extension_count;
+    create_info.ppEnabledExtensionNames = enabled_extensions;
+    if (validation_layers_installed) {
+        create_info.enabledLayerCount = 1;
+        create_info.ppEnabledLayerNames = &validation_layer_name;
+    }
+    result = vkCreateInstance(&create_info, NULL, &demo->instance);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateInstance result %d\n", result);
+        return ret;
+    }
+    if (validation_layers_installed) {
+        ret = create_debug_callback(demo);
+    } else {
+        ret = true;
+    }
+cleanup:
+    if (available_instance_extensions) {
+        free(available_instance_extensions);
+    }
+    if (enabled_extensions) {
+        free(enabled_extensions);
+    }
+
+    return ret;
+}
+
+bool create_surface(struct vulkan_demo *demo) {
+    SDL_bool result;
+    result =
+        SDL_Vulkan_CreateSurface(demo->win, demo->instance, &demo->surface);
+    if (result != SDL_TRUE) {
+        fprintf(stderr, "creating vulkan surface failed: %s\n", SDL_GetError());
+        return false;
+    }
+    return true;
+}
+
+bool find_queue_families(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
+                         struct queue_family_indices *indices) {
+    VkResult result;
+    uint32_t queue_family_count = 0;
+    uint32_t i = 0;
+    bool ret = false;
+    VkQueueFamilyProperties *queue_family_properties;
+    VkBool32 present_support;
+
+    vkGetPhysicalDeviceQueueFamilyProperties(physical_device,
+                                             &queue_family_count, NULL);
+
+    queue_family_properties =
+        malloc(queue_family_count * sizeof(VkQueueFamilyProperties));
+    vkGetPhysicalDeviceQueueFamilyProperties(
+        physical_device, &queue_family_count, queue_family_properties);
+
+    for (i = 0; i < queue_family_count; i++) {
+        if (queue_family_properties[i].queueCount == 0) {
+            continue;
+        }
+        if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            indices->graphics = i;
+        }
+
+        result = vkGetPhysicalDeviceSurfaceSupportKHR(
+            physical_device, i, surface, &present_support);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr,
+                    "vkGetPhysicalDeviceSurfaceSupportKHR failed with %d\n",
+                    result);
+            goto cleanup;
+        }
+        if (present_support == VK_TRUE) {
+            indices->present = i;
+        }
+        if (indices->graphics >= 0 && indices->present >= 0) {
+            break;
+        }
+    }
+    ret = true;
+cleanup:
+    free(queue_family_properties);
+    return ret;
+}
+
+bool query_swap_chain_support(
+    VkPhysicalDevice device, VkSurfaceKHR surface,
+    struct swap_chain_support_details *swap_chain_support) {
+    VkResult result;
+
+    result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+        device, surface, &swap_chain_support->capabilities);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr,
+                "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: %d\n",
+                result);
+        return false;
+    }
+
+    result = vkGetPhysicalDeviceSurfaceFormatsKHR(
+        device, surface, &swap_chain_support->formats_len, NULL);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\n",
+                result);
+        return false;
+    }
+
+    if (swap_chain_support->formats_len != 0) {
+        swap_chain_support->formats = malloc(swap_chain_support->formats_len *
+                                             sizeof(VkSurfaceFormatKHR));
+        result = vkGetPhysicalDeviceSurfaceFormatsKHR(
+            device, surface, &swap_chain_support->formats_len,
+            swap_chain_support->formats);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\n",
+                    result);
+            return false;
+        }
+    }
+
+    result = vkGetPhysicalDeviceSurfacePresentModesKHR(
+        device, surface, &swap_chain_support->present_modes_len, NULL);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr,
+                "vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\n",
+                result);
+        return false;
+    }
+
+    if (swap_chain_support->present_modes_len != 0) {
+        swap_chain_support->present_modes = malloc(
+            swap_chain_support->present_modes_len * sizeof(VkPresentModeKHR));
+        result = vkGetPhysicalDeviceSurfacePresentModesKHR(
+            device, surface, &swap_chain_support->present_modes_len,
+            swap_chain_support->present_modes);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr,
+                    "vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\n",
+                    result);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool is_suitable_physical_device(VkPhysicalDevice physical_device,
+                                 VkSurfaceKHR surface,
+                                 struct queue_family_indices *indices) {
+    VkResult result;
+    uint32_t device_extension_count;
+    uint32_t i;
+    VkExtensionProperties *device_extensions;
+    bool ret = false;
+    struct swap_chain_support_details swap_chain_support;
+    int found_khr_surface = 0;
+
+    VkPhysicalDeviceProperties device_properties;
+    vkGetPhysicalDeviceProperties(physical_device, &device_properties);
+
+    printf("Probing physical device %s\n", device_properties.deviceName);
+
+    result = vkEnumerateDeviceExtensionProperties(
+        physical_device, NULL, &device_extension_count, NULL);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateDeviceExtensionProperties failed: %d\n",
+                result);
+        return false;
+    }
+
+    device_extensions =
+        malloc(device_extension_count * sizeof(VkExtensionProperties));
+
+    result = vkEnumerateDeviceExtensionProperties(
+        physical_device, NULL, &device_extension_count, device_extensions);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumerateDeviceExtensionProperties failed: %d\n",
+                result);
+        goto cleanup;
+    }
+
+    printf("  Supported device extensions:\n");
+
+    for (i = 0; i < device_extension_count; i++) {
+        printf("    %s\n", device_extensions[i].extensionName);
+        if (strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+                   device_extensions[i].extensionName) == 0) {
+            found_khr_surface = 1;
+            break;
+        }
+    }
+    if (!found_khr_surface) {
+        printf("  Device doesnt support %s\n", VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+        goto cleanup;
+    }
+    if (!find_queue_families(physical_device, surface, indices)) {
+        goto cleanup;
+    }
+    if (indices->graphics < 0 || indices->present < 0) {
+        printf("  Device is missing graphics and/or present support. graphics: "
+               "%d, present: %d\n",
+               indices->graphics, indices->present);
+        goto cleanup;
+    }
+
+    if (!query_swap_chain_support(physical_device, surface,
+                                  &swap_chain_support)) {
+        goto cleanup;
+    }
+
+    if (swap_chain_support.formats_len == 0) {
+        printf(" Device doesn't support any swap chain formats\n");
+        goto cleanup;
+    }
+
+    if (swap_chain_support.present_modes_len == 0) {
+        printf(" Device doesn't support any swap chain present modes\n");
+        goto cleanup;
+    }
+    ret = true;
+
+cleanup:
+    free(device_extensions);
+    swap_chain_support_details_free(&swap_chain_support);
+
+    return ret;
+}
+
+bool create_physical_device(struct vulkan_demo *demo) {
+    uint32_t device_count = 0;
+    VkPhysicalDevice *physical_devices;
+    VkResult result;
+    uint32_t i;
+    bool ret = false;
+
+    result = vkEnumeratePhysicalDevices(demo->instance, &device_count, NULL);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumeratePhysicalDevices failed: %d\n", result);
+        return ret;
+    }
+    if (device_count == 0) {
+        fprintf(stderr, "no vulkan capable GPU found!");
+        return ret;
+    }
+
+    physical_devices = malloc(device_count * sizeof(VkPhysicalDevice));
+    result = vkEnumeratePhysicalDevices(demo->instance, &device_count,
+                                        physical_devices);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEnumeratePhysicalDevices failed: %d\n", result);
+        goto cleanup;
+    }
+
+    for (i = 0; i < device_count; i++) {
+        struct queue_family_indices indices = {-1, -1};
+        if (is_suitable_physical_device(physical_devices[i], demo->surface,
+                                        &indices)) {
+            printf("  Selecting this device for rendering. Queue families: "
+                   "graphics: %d, present: %d!\n",
+                   indices.graphics, indices.present);
+            demo->physical_device = physical_devices[i];
+            demo->indices = indices;
+            break;
+        }
+    }
+    if (demo->physical_device == NULL) {
+        fprintf(stderr, "failed to find a suitable GPU!\n");
+    } else {
+        ret = true;
+    }
+cleanup:
+    free(physical_devices);
+    return ret;
+}
+
+bool create_logical_device(struct vulkan_demo *demo) {
+    VkResult result;
+    bool ret = false;
+    float queuePriority = 1.0f;
+    uint32_t num_queues = 1;
+    VkDeviceQueueCreateInfo *queue_create_infos;
+    VkDeviceCreateInfo create_info;
+    const char *swap_chain_extension_name = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
+
+    queue_create_infos = calloc(2, sizeof(VkDeviceQueueCreateInfo));
+    queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+    queue_create_infos[0].queueFamilyIndex = demo->indices.graphics;
+    queue_create_infos[0].queueCount = 1;
+    queue_create_infos[0].pQueuePriorities = &queuePriority;
+
+    if (demo->indices.present != demo->indices.graphics) {
+        queue_create_infos[1].sType =
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+        queue_create_infos[1].queueFamilyIndex = demo->indices.present;
+        queue_create_infos[1].queueCount = 1;
+        queue_create_infos[1].pQueuePriorities = &queuePriority;
+        num_queues = 2;
+    }
+
+    memset(&create_info, 0, sizeof(VkDeviceCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+    create_info.queueCreateInfoCount = num_queues;
+    create_info.pQueueCreateInfos = queue_create_infos;
+    create_info.enabledExtensionCount = 1;
+    create_info.ppEnabledExtensionNames = &swap_chain_extension_name;
+
+    result = vkCreateDevice(demo->physical_device, &create_info, NULL,
+                            &demo->device);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateDevice failed: %d\n", result);
+        goto cleanup;
+    }
+
+    vkGetDeviceQueue(demo->device, demo->indices.graphics, 0,
+                     &demo->graphics_queue);
+    vkGetDeviceQueue(demo->device, demo->indices.present, 0,
+                     &demo->present_queue);
+    ret = true;
+cleanup:
+    free(queue_create_infos);
+    return ret;
+}
+
+bool create_sampler(struct vulkan_demo *demo) {
+    VkResult result;
+    VkSamplerCreateInfo sampler_info;
+
+    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));
+    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+    sampler_info.pNext = NULL;
+    sampler_info.maxAnisotropy = 1.0;
+    sampler_info.magFilter = VK_FILTER_LINEAR;
+    sampler_info.minFilter = VK_FILTER_LINEAR;
+    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.mipLodBias = 0.0f;
+    sampler_info.compareEnable = VK_FALSE;
+    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
+    sampler_info.minLod = 0.0f;
+    sampler_info.maxLod = 0.0f;
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+
+    result = vkCreateSampler(demo->device, &sampler_info, NULL, &demo->sampler);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateSampler failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+VkSurfaceFormatKHR
+choose_swap_surface_format(VkSurfaceFormatKHR *available_formats,
+                           uint32_t available_formats_len) {
+    VkSurfaceFormatKHR undefined_format = {VK_FORMAT_B8G8R8A8_UNORM,
+                                           VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
+    uint32_t i;
+    if (available_formats_len == 1 &&
+        available_formats[0].format == VK_FORMAT_UNDEFINED) {
+        return undefined_format;
+    }
+
+    for (i = 0; i < available_formats_len; i++) {
+        if (available_formats[i].format == VK_FORMAT_B8G8R8A8_UNORM &&
+            available_formats[i].colorSpace ==
+                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+            return available_formats[i];
+        }
+    }
+
+    return available_formats[0];
+}
+
+VkPresentModeKHR
+choose_swap_present_mode(VkPresentModeKHR *available_present_modes,
+                         uint32_t available_present_modes_len) {
+    uint32_t i;
+    for (i = 0; i < available_present_modes_len; i++) {
+        /*
+        best mode to ensure good input latency while ensuring we are not
+        producing tearing
+        */
+        if (available_present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
+            return available_present_modes[i];
+        }
+    }
+
+    /* must be supported */
+    return VK_PRESENT_MODE_FIFO_KHR;
+}
+
+VkExtent2D choose_swap_extent(struct vulkan_demo *demo,
+                              VkSurfaceCapabilitiesKHR *capabilities) {
+    int width, height;
+    VkExtent2D actual_extent;
+    if (capabilities->currentExtent.width != 0xFFFFFFFF) {
+        return capabilities->currentExtent;
+    } else {
+        /* not window size! */
+        SDL_Vulkan_GetDrawableSize(demo->win, &width, &height);
+
+        actual_extent.width = (uint32_t)width;
+        actual_extent.height = (uint32_t)height;
+
+        actual_extent.width = NK_MAX(
+            capabilities->minImageExtent.width,
+            NK_MIN(capabilities->maxImageExtent.width, actual_extent.width));
+        actual_extent.height = NK_MAX(
+            capabilities->minImageExtent.height,
+            NK_MIN(capabilities->maxImageExtent.height, actual_extent.height));
+
+        return actual_extent;
+    }
+}
+
+bool create_swap_chain(struct vulkan_demo *demo) {
+    struct swap_chain_support_details swap_chain_support;
+    VkSurfaceFormatKHR surface_format;
+    VkPresentModeKHR present_mode;
+    VkExtent2D extent;
+    VkResult result;
+    VkSwapchainCreateInfoKHR create_info;
+    uint32_t queue_family_indices[2];
+    bool ret = false;
+
+    queue_family_indices[0] = (uint32_t)demo->indices.graphics;
+    queue_family_indices[1] = (uint32_t)demo->indices.present;
+
+    if (!query_swap_chain_support(demo->physical_device, demo->surface,
+                                  &swap_chain_support)) {
+        goto cleanup;
+    }
+    surface_format = choose_swap_surface_format(swap_chain_support.formats,
+                                                swap_chain_support.formats_len);
+    present_mode = choose_swap_present_mode(
+        swap_chain_support.present_modes, swap_chain_support.present_modes_len);
+    extent = choose_swap_extent(demo, &swap_chain_support.capabilities);
+
+    demo->swap_chain_images_len =
+        swap_chain_support.capabilities.minImageCount + 1;
+    if (swap_chain_support.capabilities.maxImageCount > 0 &&
+        demo->swap_chain_images_len >
+            swap_chain_support.capabilities.maxImageCount) {
+        demo->swap_chain_images_len =
+            swap_chain_support.capabilities.maxImageCount;
+    }
+
+    memset(&create_info, 0, sizeof(VkSwapchainCreateInfoKHR));
+    create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+    create_info.surface = demo->surface;
+
+    create_info.minImageCount = demo->swap_chain_images_len;
+    create_info.imageFormat = surface_format.format;
+    create_info.imageColorSpace = surface_format.colorSpace;
+    create_info.imageExtent = extent;
+    create_info.imageArrayLayers = 1;
+    create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+    if (demo->indices.graphics != demo->indices.present) {
+        create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+        create_info.queueFamilyIndexCount = 2;
+        create_info.pQueueFamilyIndices = queue_family_indices;
+    } else {
+        create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    }
+
+    create_info.preTransform = swap_chain_support.capabilities.currentTransform;
+    create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+    create_info.presentMode = present_mode;
+    create_info.clipped = VK_TRUE;
+
+    result = vkCreateSwapchainKHR(demo->device, &create_info, NULL,
+                                  &demo->swap_chain);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateSwapchainKHR failed: %d\n", result);
+        goto cleanup;
+    }
+
+    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,
+                                     &demo->swap_chain_images_len, NULL);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkGetSwapchainImagesKHR failed: %d\n", result);
+        goto cleanup;
+    }
+    if (demo->swap_chain_images == NULL) {
+        demo->swap_chain_images =
+            malloc(demo->swap_chain_images_len * sizeof(VkImage));
+    }
+    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,
+                                     &demo->swap_chain_images_len,
+                                     demo->swap_chain_images);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkGetSwapchainImagesKHR failed: %d\n", result);
+        return false;
+    }
+
+    demo->swap_chain_image_format = surface_format.format;
+    demo->swap_chain_image_extent = extent;
+
+    ret = true;
+cleanup:
+    swap_chain_support_details_free(&swap_chain_support);
+
+    return ret;
+}
+
+bool create_swap_chain_image_views(struct vulkan_demo *demo) {
+    uint32_t i;
+    VkResult result;
+    VkImageViewCreateInfo create_info;
+
+    memset(&create_info, 0, sizeof(VkImageViewCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    create_info.format = demo->swap_chain_image_format;
+    create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    create_info.subresourceRange.baseMipLevel = 0;
+    create_info.subresourceRange.levelCount = 1;
+    create_info.subresourceRange.baseArrayLayer = 0;
+    create_info.subresourceRange.layerCount = 1;
+
+    if (!demo->swap_chain_image_views) {
+        demo->swap_chain_image_views =
+            malloc(demo->swap_chain_images_len * sizeof(VkImageView));
+    }
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        create_info.image = demo->swap_chain_images[i];
+        result = vkCreateImageView(demo->device, &create_info, NULL,
+                                   &demo->swap_chain_image_views[i]);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkCreateImageView failed: %d\n", result);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool create_overlay_images(struct vulkan_demo *demo) {
+    uint32_t i, j;
+    VkResult result;
+    VkMemoryRequirements mem_requirements;
+    VkPhysicalDeviceMemoryProperties mem_properties;
+    int found;
+    VkImageCreateInfo image_info;
+    VkMemoryAllocateInfo alloc_info;
+    VkImageViewCreateInfo image_view_info;
+
+    memset(&image_info, 0, sizeof(VkImageCreateInfo));
+    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_info.imageType = VK_IMAGE_TYPE_2D;
+    image_info.extent.width = demo->swap_chain_image_extent.width;
+    image_info.extent.height = demo->swap_chain_image_extent.height;
+    image_info.extent.depth = 1;
+    image_info.mipLevels = 1;
+    image_info.arrayLayers = 1;
+    image_info.format = demo->swap_chain_image_format;
+    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    image_info.usage =
+        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
+    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+
+    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));
+    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    image_view_info.format = demo->swap_chain_image_format;
+    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    image_view_info.subresourceRange.baseMipLevel = 0;
+    image_view_info.subresourceRange.levelCount = 1;
+    image_view_info.subresourceRange.baseArrayLayer = 0;
+    image_view_info.subresourceRange.layerCount = 1;
+
+    if (!demo->overlay_images) {
+        demo->overlay_images =
+            malloc(demo->swap_chain_images_len * sizeof(VkImage));
+    }
+
+    if (!demo->overlay_image_memories) {
+        demo->overlay_image_memories =
+            malloc(demo->swap_chain_images_len * sizeof(VkDeviceMemory));
+    }
+    if (!demo->overlay_image_views) {
+        demo->overlay_image_views =
+            malloc(demo->swap_chain_images_len * sizeof(VkImageView));
+    }
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        result = vkCreateImage(demo->device, &image_info, NULL,
+                               &demo->overlay_images[i]);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkCreateImage failed for index %lu: %d\n",
+                    (unsigned long)i, result);
+            return false;
+        }
+
+        vkGetImageMemoryRequirements(demo->device, demo->overlay_images[i],
+                                     &mem_requirements);
+
+        alloc_info.allocationSize = mem_requirements.size;
+
+        vkGetPhysicalDeviceMemoryProperties(demo->physical_device,
+                                            &mem_properties);
+        found = 0;
+        for (j = 0; j < mem_properties.memoryTypeCount; j++) {
+            if ((mem_requirements.memoryTypeBits & (1 << j)) &&
+                (mem_properties.memoryTypes[j].propertyFlags &
+                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==
+                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+                found = 1;
+                break;
+            }
+        }
+        if (!found) {
+            fprintf(stderr,
+                    "failed to find suitable memory type for index %lu!\n",
+                    (unsigned long)i);
+            return false;
+        }
+        alloc_info.memoryTypeIndex = j;
+        result = vkAllocateMemory(demo->device, &alloc_info, NULL,
+                                  &demo->overlay_image_memories[i]);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr,
+                    "failed to allocate vulkan memory for index %lu: %d!\n",
+                    (unsigned long)i, result);
+            return false;
+        }
+        result = vkBindImageMemory(demo->device, demo->overlay_images[i],
+                                   demo->overlay_image_memories[i], 0);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "Couldn't bind image memory for index %lu: %d\n",
+                    (unsigned long)i, result);
+            return false;
+        }
+
+        image_view_info.image = demo->overlay_images[i];
+        result = vkCreateImageView(demo->device, &image_view_info, NULL,
+                                   &demo->overlay_image_views[i]);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkCreateImageView failed for index %lu: %d\n",
+                    (unsigned long)i, result);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool create_render_pass(struct vulkan_demo *demo) {
+    VkAttachmentDescription attachment;
+    VkAttachmentReference color_attachment_ref;
+    VkSubpassDescription subpass;
+    VkSubpassDependency dependency;
+    VkRenderPassCreateInfo render_pass_info;
+    VkResult result;
+
+    memset(&attachment, 0, sizeof(VkAttachmentDescription));
+    attachment.format = demo->swap_chain_image_format;
+    attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+    memset(&color_attachment_ref, 0, sizeof(VkAttachmentReference));
+    color_attachment_ref.attachment = 0;
+    color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    memset(&subpass, 0, sizeof(VkSubpassDescription));
+    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    subpass.colorAttachmentCount = 1;
+    subpass.pColorAttachments = &color_attachment_ref;
+
+    memset(&dependency, 0, sizeof(VkSubpassDependency));
+    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+    dependency.dstSubpass = 0;
+    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    dependency.srcAccessMask = 0;
+    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));
+    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    render_pass_info.attachmentCount = 1;
+    render_pass_info.pAttachments = &attachment;
+    render_pass_info.subpassCount = 1;
+    render_pass_info.pSubpasses = &subpass;
+    render_pass_info.dependencyCount = 1;
+    render_pass_info.pDependencies = &dependency;
+
+    result = vkCreateRenderPass(demo->device, &render_pass_info, NULL,
+                                &demo->render_pass);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateRenderPass failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_framebuffers(struct vulkan_demo *demo) {
+    uint32_t i;
+    VkResult result;
+    VkFramebufferCreateInfo framebuffer_info;
+
+    if (!demo->framebuffers) {
+        demo->framebuffers =
+            malloc(demo->swap_chain_images_len * sizeof(VkFramebuffer));
+    }
+
+    memset(&framebuffer_info, 0, sizeof(VkFramebufferCreateInfo));
+    framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    framebuffer_info.renderPass = demo->render_pass;
+    framebuffer_info.attachmentCount = 1;
+    framebuffer_info.width = demo->swap_chain_image_extent.width;
+    framebuffer_info.height = demo->swap_chain_image_extent.height;
+    framebuffer_info.layers = 1;
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        framebuffer_info.pAttachments = &demo->swap_chain_image_views[i];
+
+        result = vkCreateFramebuffer(demo->device, &framebuffer_info, NULL,
+                                     &demo->framebuffers[i]);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkCreateFramebuffer failed from index %lu: %d\n",
+                    (unsigned long)i, result);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool create_descriptor_set_layout(struct vulkan_demo *demo) {
+    VkDescriptorSetLayoutBinding overlay_layout_binding;
+    VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_nfo;
+    VkResult result;
+
+    memset(&overlay_layout_binding, 0, sizeof(VkDescriptorSetLayoutBinding));
+    overlay_layout_binding.binding = 0;
+    overlay_layout_binding.descriptorCount = 1;
+    overlay_layout_binding.descriptorType =
+        VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    overlay_layout_binding.pImmutableSamplers = NULL;
+    overlay_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+
+    memset(&descriptor_set_layout_create_nfo, 0,
+           sizeof(VkDescriptorSetLayoutCreateInfo));
+    descriptor_set_layout_create_nfo.sType =
+        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_set_layout_create_nfo.bindingCount = 1;
+    descriptor_set_layout_create_nfo.pBindings = &overlay_layout_binding;
+
+    result = vkCreateDescriptorSetLayout(demo->device,
+                                         &descriptor_set_layout_create_nfo,
+                                         NULL, &demo->descriptor_set_layout);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateDescriptorSetLayout failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_descriptor_pool(struct vulkan_demo *demo) {
+    VkDescriptorPoolSize pool_size;
+    VkDescriptorPoolCreateInfo pool_info;
+    VkResult result;
+
+    memset(&pool_size, 0, sizeof(VkDescriptorPoolSize));
+    pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    pool_size.descriptorCount = demo->swap_chain_images_len;
+
+    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));
+    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    pool_info.poolSizeCount = 1;
+    pool_info.pPoolSizes = &pool_size;
+    pool_info.maxSets = demo->swap_chain_images_len;
+    result = vkCreateDescriptorPool(demo->device, &pool_info, NULL,
+                                    &demo->descriptor_pool);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateDescriptorPool failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+void update_descriptor_sets(struct vulkan_demo *demo) {
+    uint32_t i;
+    VkDescriptorImageInfo descriptor_image_info;
+    VkWriteDescriptorSet descriptor_write;
+
+    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));
+    descriptor_image_info.imageLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    descriptor_image_info.sampler = demo->sampler;
+
+    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.dstArrayElement = 0;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.pImageInfo = &descriptor_image_info;
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        descriptor_write.dstSet = demo->descriptor_sets[i];
+        descriptor_image_info.imageView = demo->overlay_image_views[i];
+
+        vkUpdateDescriptorSets(demo->device, 1, &descriptor_write, 0, NULL);
+    }
+}
+
+bool create_descriptor_sets(struct vulkan_demo *demo) {
+    bool ret = false;
+    VkDescriptorSetLayout *descriptor_set_layouts;
+    VkDescriptorSetAllocateInfo alloc_info;
+    uint32_t i;
+    VkResult result;
+
+    demo->descriptor_sets =
+        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSet));
+    descriptor_set_layouts =
+        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSetLayout));
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        descriptor_set_layouts[i] = demo->descriptor_set_layout;
+    }
+
+    memset(&alloc_info, 0, sizeof(VkDescriptorSetAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    alloc_info.descriptorPool = demo->descriptor_pool;
+    alloc_info.descriptorSetCount = demo->swap_chain_images_len;
+    alloc_info.pSetLayouts = descriptor_set_layouts;
+    result = vkAllocateDescriptorSets(demo->device, &alloc_info,
+                                      demo->descriptor_sets);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkAllocateDescriptorSets failed: %d\n", result);
+        goto cleanup;
+    }
+
+    update_descriptor_sets(demo);
+
+    ret = true;
+cleanup:
+    free(descriptor_set_layouts);
+
+    return ret;
+}
+
+bool create_shader_module(VkDevice device, char *shader_buffer,
+                          size_t shader_buffer_len,
+                          VkShaderModule *shader_module) {
+    VkShaderModuleCreateInfo create_info;
+    VkResult result;
+
+    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    create_info.codeSize = shader_buffer_len;
+    create_info.pCode = (const uint32_t *)shader_buffer;
+
+    result = vkCreateShaderModule(device, &create_info, NULL, shader_module);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateShaderModule failed: %d\n", result);
+        return false;
+    }
+
+    return true;
+}
+
+bool create_graphics_pipeline(struct vulkan_demo *demo) {
+    bool ret = false;
+    char *vert_shader_code = NULL;
+    char *frag_shader_code = NULL;
+    VkShaderModule vert_shader_module = VK_NULL_HANDLE;
+    VkShaderModule frag_shader_module = VK_NULL_HANDLE;
+    FILE *fp;
+    size_t file_len;
+    VkPipelineShaderStageCreateInfo vert_shader_stage_info;
+    VkPipelineShaderStageCreateInfo frag_shader_stage_info;
+    VkPipelineShaderStageCreateInfo shader_stages[2];
+    VkPipelineVertexInputStateCreateInfo vertex_input_info;
+    VkPipelineInputAssemblyStateCreateInfo input_assembly;
+    VkViewport viewport;
+    VkRect2D scissor;
+    VkPipelineViewportStateCreateInfo viewport_state;
+    VkPipelineRasterizationStateCreateInfo rasterizer;
+    VkPipelineMultisampleStateCreateInfo multisampling;
+    VkPipelineColorBlendAttachmentState color_blend_attachment;
+    VkPipelineColorBlendStateCreateInfo color_blending;
+    VkPipelineLayoutCreateInfo pipeline_layout_info;
+    VkResult result;
+    VkGraphicsPipelineCreateInfo pipeline_info;
+    size_t read_result;
+
+    fp = fopen("shaders/demo.vert.spv", "r");
+    if (!fp) {
+        fprintf(stderr, "Couldn't open shaders/demo.vert.spv\n");
+        return false;
+    }
+    fseek(fp, 0, SEEK_END);
+    file_len = ftell(fp);
+    vert_shader_code = malloc(file_len);
+    fseek(fp, 0, 0);
+    read_result = fread(vert_shader_code, file_len, 1, fp);
+    fclose(fp);
+    if (read_result != 1) {
+        fprintf(stderr, "Could not read vertex shader\n");
+        goto cleanup;
+    }
+
+    if (!create_shader_module(demo->device, vert_shader_code, file_len,
+                              &vert_shader_module)) {
+        goto cleanup;
+    }
+
+    fp = fopen("shaders/demo.frag.spv", "r");
+    if (!fp) {
+        fprintf(stderr, "Couldn't open shaders/demo.frag.spv\n");
+        return false;
+    }
+    fseek(fp, 0, SEEK_END);
+    file_len = ftell(fp);
+    frag_shader_code = malloc(file_len);
+    fseek(fp, 0, 0);
+    read_result = fread(frag_shader_code, file_len, 1, fp);
+    fclose(fp);
+    if (read_result != 1) {
+        fprintf(stderr, "Could not read fragment shader\n");
+        goto cleanup;
+    }
+
+    if (!create_shader_module(demo->device, frag_shader_code, file_len,
+                              &frag_shader_module)) {
+        goto cleanup;
+    }
+
+    memset(&vert_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
+    vert_shader_stage_info.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
+    vert_shader_stage_info.module = vert_shader_module;
+    vert_shader_stage_info.pName = "main";
+
+    memset(&frag_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
+    frag_shader_stage_info.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+    frag_shader_stage_info.module = frag_shader_module;
+    frag_shader_stage_info.pName = "main";
+
+    shader_stages[0] = vert_shader_stage_info;
+    shader_stages[1] = frag_shader_stage_info;
+
+    memset(&vertex_input_info, 0, sizeof(VkPipelineVertexInputStateCreateInfo));
+    vertex_input_info.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+
+    memset(&input_assembly, 0, sizeof(VkPipelineInputAssemblyStateCreateInfo));
+    input_assembly.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+    input_assembly.primitiveRestartEnable = VK_FALSE;
+
+    memset(&viewport, 0, sizeof(VkViewport));
+    viewport.x = 0.0f;
+    viewport.y = 0.0f;
+    viewport.width = (float)demo->swap_chain_image_extent.width;
+    viewport.height = (float)demo->swap_chain_image_extent.height;
+    viewport.minDepth = 0.0f;
+    viewport.maxDepth = 1.0f;
+
+    memset(&scissor, 0, sizeof(VkRect2D));
+    scissor.extent.width = demo->swap_chain_image_extent.width;
+    scissor.extent.height = demo->swap_chain_image_extent.height;
+
+    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));
+    viewport_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+    viewport_state.viewportCount = 1;
+    viewport_state.pViewports = &viewport;
+    viewport_state.scissorCount = 1;
+    viewport_state.pScissors = &scissor;
+
+    memset(&rasterizer, 0, sizeof(VkPipelineRasterizationStateCreateInfo));
+    rasterizer.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+    rasterizer.depthClampEnable = VK_FALSE;
+    rasterizer.rasterizerDiscardEnable = VK_FALSE;
+    rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+    rasterizer.lineWidth = 1.0f;
+    rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;
+    rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+    rasterizer.depthBiasEnable = VK_FALSE;
+
+    memset(&multisampling, 0, sizeof(VkPipelineMultisampleStateCreateInfo));
+    multisampling.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    multisampling.sampleShadingEnable = VK_FALSE;
+    multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+    memset(&color_blend_attachment, 0,
+           sizeof(VkPipelineColorBlendAttachmentState));
+    color_blend_attachment.colorWriteMask =
+        VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+    color_blend_attachment.blendEnable = VK_TRUE;
+    color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+    color_blend_attachment.dstColorBlendFactor =
+        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+    color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
+    color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+    color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+    color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
+
+    memset(&color_blending, 0, sizeof(VkPipelineColorBlendStateCreateInfo));
+    color_blending.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+    color_blending.logicOpEnable = VK_FALSE;
+    color_blending.logicOp = VK_LOGIC_OP_COPY;
+    color_blending.attachmentCount = 1;
+    color_blending.pAttachments = &color_blend_attachment;
+    color_blending.blendConstants[0] = 1.0f;
+    color_blending.blendConstants[1] = 1.0f;
+    color_blending.blendConstants[2] = 1.0f;
+    color_blending.blendConstants[3] = 1.0f;
+
+    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));
+    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipeline_layout_info.setLayoutCount = 0;
+    pipeline_layout_info.pushConstantRangeCount = 0;
+    pipeline_layout_info.setLayoutCount = 1;
+    pipeline_layout_info.pSetLayouts = &demo->descriptor_set_layout;
+
+    result = vkCreatePipelineLayout(demo->device, &pipeline_layout_info, NULL,
+                                    &demo->pipeline_layout);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreatePipelineLayout failed: %d\n", result);
+        goto cleanup;
+    }
+
+    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));
+    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+    pipeline_info.stageCount = 2;
+    pipeline_info.pStages = shader_stages;
+    pipeline_info.pVertexInputState = &vertex_input_info;
+    pipeline_info.pInputAssemblyState = &input_assembly;
+    pipeline_info.pViewportState = &viewport_state;
+    pipeline_info.pRasterizationState = &rasterizer;
+    pipeline_info.pMultisampleState = &multisampling;
+    pipeline_info.pColorBlendState = &color_blending;
+    pipeline_info.layout = demo->pipeline_layout;
+    pipeline_info.renderPass = demo->render_pass;
+    pipeline_info.basePipelineHandle = NULL;
+
+    result = vkCreateGraphicsPipelines(demo->device, NULL, 1, &pipeline_info,
+                                       NULL, &demo->pipeline);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateGraphicsPipelines failed: %d\n", result);
+        goto cleanup;
+    }
+    ret = true;
+cleanup:
+    if (frag_shader_module) {
+        vkDestroyShaderModule(demo->device, frag_shader_module, NULL);
+    }
+    if (frag_shader_code) {
+        free(frag_shader_code);
+    }
+    if (vert_shader_module) {
+        vkDestroyShaderModule(demo->device, vert_shader_module, NULL);
+    }
+    if (vert_shader_code) {
+        free(vert_shader_code);
+    }
+
+    return ret;
+}
+
+bool create_command_pool(struct vulkan_demo *demo) {
+    VkCommandPoolCreateInfo pool_info;
+    VkResult result;
+
+    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));
+    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    pool_info.queueFamilyIndex = demo->indices.graphics;
+
+    result = vkCreateCommandPool(demo->device, &pool_info, NULL,
+                                 &demo->command_pool);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateCommandPool failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_command_buffers(struct vulkan_demo *demo) {
+    VkCommandBufferAllocateInfo alloc_info;
+    VkResult result;
+
+    demo->command_buffers =
+        malloc(demo->swap_chain_images_len * sizeof(VkCommandBuffer));
+
+    memset(&alloc_info, 0, sizeof(VkCommandBufferAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    alloc_info.commandPool = demo->command_pool;
+    alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    alloc_info.commandBufferCount = demo->swap_chain_images_len;
+
+    result = vkAllocateCommandBuffers(demo->device, &alloc_info,
+                                      demo->command_buffers);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkAllocateCommandBuffers failed: %d\n", result);
+        return false;
+    }
+
+    return true;
+}
+
+bool create_semaphores(struct vulkan_demo *demo) {
+    VkSemaphoreCreateInfo semaphore_info;
+    VkResult result;
+
+    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));
+    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,
+                               &demo->image_available);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateSemaphore failed: %d\n", result);
+        return false;
+    }
+    result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,
+                               &demo->render_finished);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateSemaphore failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_fence(struct vulkan_demo *demo) {
+    VkResult result;
+    VkFenceCreateInfo fence_create_info;
+
+    memset(&fence_create_info, 0, sizeof(VkFenceCreateInfo));
+    fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+    result = vkCreateFence(demo->device, &fence_create_info, NULL,
+                           &demo->render_fence);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateFence failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+bool create_swap_chain_related_resources(struct vulkan_demo *demo) {
+    if (!create_swap_chain(demo)) {
+        return false;
+    }
+    if (!create_swap_chain_image_views(demo)) {
+        return false;
+    }
+    if (!create_overlay_images(demo)) {
+        return false;
+    }
+    if (!create_render_pass(demo)) {
+        return false;
+    }
+    if (!create_framebuffers(demo)) {
+        return false;
+    }
+    if (!create_graphics_pipeline(demo)) {
+        return false;
+    }
+    return true;
+}
+
+bool destroy_swap_chain_related_resources(struct vulkan_demo *demo) {
+    uint32_t i;
+    VkResult result;
+
+    result = vkQueueWaitIdle(demo->graphics_queue);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkQueueWaitIdle failed: %d\n", result);
+        return false;
+    }
+
+    for (i = 0; i < demo->swap_chain_images_len; i++) {
+        vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
+        vkDestroyImageView(demo->device, demo->overlay_image_views[i], NULL);
+        vkDestroyImage(demo->device, demo->overlay_images[i], NULL);
+        vkFreeMemory(demo->device, demo->overlay_image_memories[i], NULL);
+        vkDestroyImageView(demo->device, demo->swap_chain_image_views[i], NULL);
+    }
+    vkDestroySwapchainKHR(demo->device, demo->swap_chain, NULL);
+    vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
+    vkDestroyPipeline(demo->device, demo->pipeline, NULL);
+    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
+    return true;
+}
+
+bool create_demo_texture(struct vulkan_demo *demo) {
+    VkResult result;
+    VkMemoryRequirements mem_requirements;
+    VkPhysicalDeviceMemoryProperties mem_properties;
+    int found;
+    uint32_t i;
+    VkImageCreateInfo image_info;
+    VkMemoryAllocateInfo alloc_info;
+    VkImageViewCreateInfo image_view_info;
+    VkBufferCreateInfo buffer_info;
+    struct {
+        VkDeviceMemory memory;
+        VkBuffer buffer;
+    } staging_buffer;
+    void *data;
+    VkCommandBuffer command_buffer;
+    VkCommandBufferBeginInfo begin_info;
+    VkImageMemoryBarrier image_transfer_dst_memory_barrier;
+    VkBufferImageCopy buffer_copy_region;
+    VkImageMemoryBarrier image_shader_memory_barrier;
+    VkFence fence;
+    VkFenceCreateInfo fence_create;
+    VkSubmitInfo submit_info;
+
+    memset(&image_info, 0, sizeof(VkImageCreateInfo));
+    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_info.imageType = VK_IMAGE_TYPE_2D;
+    image_info.extent.width = 2;
+    image_info.extent.height = 2;
+    image_info.extent.depth = 1;
+    image_info.mipLevels = 1;
+    image_info.arrayLayers = 1;
+    image_info.format = VK_FORMAT_R8_UNORM;
+    image_info.tiling = VK_IMAGE_TILING_LINEAR;
+    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    image_info.usage =
+        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
+    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+
+    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));
+    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    image_view_info.format = VK_FORMAT_R8_UNORM;
+    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    image_view_info.subresourceRange.baseMipLevel = 0;
+    image_view_info.subresourceRange.levelCount = 1;
+    image_view_info.subresourceRange.baseArrayLayer = 0;
+    image_view_info.subresourceRange.layerCount = 1;
+
+    result = vkCreateImage(demo->device, &image_info, NULL,
+                           &demo->demo_texture_image);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateImage failed: %d\n", result);
+        return false;
+    }
+
+    vkGetImageMemoryRequirements(demo->device, demo->demo_texture_image,
+                                 &mem_requirements);
+
+    alloc_info.allocationSize = mem_requirements.size;
+
+    vkGetPhysicalDeviceMemoryProperties(demo->physical_device, &mem_properties);
+    found = 0;
+    for (i = 0; i < mem_properties.memoryTypeCount; i++) {
+        if ((mem_requirements.memoryTypeBits & (1 << i)) &&
+            (mem_properties.memoryTypes[i].propertyFlags &
+             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==
+                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "failed to find suitable memory for demo texture!\n");
+        return false;
+    }
+    alloc_info.memoryTypeIndex = i;
+    result = vkAllocateMemory(demo->device, &alloc_info, NULL,
+                              &demo->demo_texture_memory);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr,
+                "failed to allocate vulkan memory for demo texture: %d!\n",
+                result);
+        return false;
+    }
+    result = vkBindImageMemory(demo->device, demo->demo_texture_image,
+                               demo->demo_texture_memory, 0);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "Couldn't bind image memory for demo texture: %d\n",
+                result);
+        return false;
+    }
+
+    image_view_info.image = demo->demo_texture_image;
+    result = vkCreateImageView(demo->device, &image_view_info, NULL,
+                               &demo->demo_texture_image_view);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateImageView failed for demo texture: %d\n",
+                result);
+        return false;
+    }
+
+    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.size = alloc_info.allocationSize;
+    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    result = vkCreateBuffer(demo->device, &buffer_info, NULL,
+                            &staging_buffer.buffer);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateBuffer failed for demo texture: %d\n", result);
+        return false;
+    }
+    vkGetBufferMemoryRequirements(demo->device, staging_buffer.buffer,
+                                  &mem_requirements);
+
+    alloc_info.allocationSize = mem_requirements.size;
+    found = 0;
+    for (i = 0; i < mem_properties.memoryTypeCount; i++) {
+        if ((mem_requirements.memoryTypeBits & (1 << i)) &&
+            (mem_properties.memoryTypes[i].propertyFlags &
+             (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+              VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==
+                (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "failed to find suitable staging buffer memory for "
+                        "demo texture!\n");
+        return false;
+    }
+    alloc_info.memoryTypeIndex = i;
+    result = vkAllocateMemory(demo->device, &alloc_info, NULL,
+                              &staging_buffer.memory);
+    if (!found) {
+        fprintf(stderr, "vkAllocateMemory failed for demo texture: %d\n",
+                result);
+        return false;
+    }
+    result = vkBindBufferMemory(demo->device, staging_buffer.buffer,
+                                staging_buffer.memory, 0);
+    if (!found) {
+        fprintf(stderr, "vkBindBufferMemory failed for demo texture: %d\n",
+                result);
+        return false;
+    }
+
+    result = vkMapMemory(demo->device, staging_buffer.memory, 0,
+                         sizeof(uint32_t), 0, &data);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkMapMemory failed for demo texture: %d\n", result);
+        return false;
+    }
+    *((uint32_t *)data) = 0x00FFFF00;
+    vkUnmapMemory(demo->device, staging_buffer.memory);
+
+    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    command_buffer = demo->command_buffers[0];
+    result = vkBeginCommandBuffer(command_buffer, &begin_info);
+
+    memset(&image_transfer_dst_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_transfer_dst_memory_barrier.sType =
+        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_transfer_dst_memory_barrier.image = demo->demo_texture_image;
+    image_transfer_dst_memory_barrier.srcQueueFamilyIndex =
+        VK_QUEUE_FAMILY_IGNORED;
+    image_transfer_dst_memory_barrier.dstQueueFamilyIndex =
+        VK_QUEUE_FAMILY_IGNORED;
+    image_transfer_dst_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    image_transfer_dst_memory_barrier.newLayout =
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_transfer_dst_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_transfer_dst_memory_barrier.subresourceRange.levelCount = 1;
+    image_transfer_dst_memory_barrier.subresourceRange.layerCount = 1;
+    image_transfer_dst_memory_barrier.dstAccessMask =
+        VK_ACCESS_TRANSFER_WRITE_BIT;
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
+                         &image_transfer_dst_memory_barrier);
+
+    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));
+    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    buffer_copy_region.imageSubresource.layerCount = 1;
+    buffer_copy_region.imageExtent.width = 2;
+    buffer_copy_region.imageExtent.height = 2;
+    buffer_copy_region.imageExtent.depth = 1;
+
+    vkCmdCopyBufferToImage(
+        command_buffer, staging_buffer.buffer, demo->demo_texture_image,
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);
+
+    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_shader_memory_barrier.image = demo->demo_texture_image;
+    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.oldLayout =
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_shader_memory_barrier.newLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    image_shader_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_shader_memory_barrier.subresourceRange.levelCount = 1;
+    image_shader_memory_barrier.subresourceRange.layerCount = 1;
+    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,
+                         NULL, 1, &image_shader_memory_barrier);
+
+    result = vkEndCommandBuffer(command_buffer);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEndCommandBuffer failed for demo texture: %d\n",
+                result);
+        return false;
+    }
+
+    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));
+    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    result = vkCreateFence(demo->device, &fence_create, NULL, &fence);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkCreateFence failed for demo texture: %d\n", result);
+        return false;
+    }
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+
+    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkQueueSubmit failed for demo texture: %d\n", result);
+        return false;
+    }
+    result = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkWaitForFences failed for demo texture: %d\n",
+                result);
+        return false;
+    }
+
+    vkDestroyBuffer(demo->device, staging_buffer.buffer, NULL);
+    vkFreeMemory(demo->device, staging_buffer.memory, NULL);
+    vkDestroyFence(demo->device, fence, NULL);
+
+    return true;
+}
+
+bool create_vulkan_demo(struct vulkan_demo *demo) {
+    if (!create_instance(demo)) {
+        return false;
+    }
+    if (!create_surface(demo)) {
+        return false;
+    }
+    if (!create_physical_device(demo)) {
+        return false;
+    }
+    if (!create_logical_device(demo)) {
+        return false;
+    }
+    if (!create_sampler(demo)) {
+        return false;
+    }
+    if (!create_descriptor_set_layout(demo)) {
+        return false;
+    }
+    if (!create_swap_chain_related_resources(demo)) {
+        return false;
+    }
+    if (!create_descriptor_pool(demo)) {
+        return false;
+    }
+    if (!create_descriptor_sets(demo)) {
+        return false;
+    }
+    if (!create_command_pool(demo)) {
+        return false;
+    }
+    if (!create_command_buffers(demo)) {
+        return false;
+    }
+    if (!create_semaphores(demo)) {
+        return false;
+    }
+    if (!create_fence(demo)) {
+        return false;
+    }
+    if (!create_demo_texture(demo)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool recreate_swap_chain(struct vulkan_demo *demo) {
+    printf("recreating swapchain\n");
+    if (!destroy_swap_chain_related_resources(demo)) {
+        return false;
+    }
+    if (!create_swap_chain_related_resources(demo)) {
+        return false;
+    }
+
+    update_descriptor_sets(demo);
+
+    nk_sdl_resize(demo->swap_chain_image_extent.width,
+                  demo->swap_chain_image_extent.height);
+
+    return true;
+}
+
+bool render(struct vulkan_demo *demo, struct nk_colorf *bg,
+            VkSemaphore wait_semaphore, uint32_t image_index) {
+    VkCommandBufferBeginInfo command_buffer_begin_info;
+    VkCommandBuffer command_buffer;
+    VkRenderPassBeginInfo render_pass_info;
+    VkSubmitInfo submit_info;
+    VkPipelineStageFlags wait_stage =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkResult result;
+    VkPresentInfoKHR present_info;
+    VkClearValue clear_color;
+
+    memcpy(&clear_color.color, bg, sizeof(VkClearColorValue));
+
+    memset(&command_buffer_begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    command_buffer_begin_info.sType =
+        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    command_buffer = demo->command_buffers[image_index];
+    result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkBeginCommandBuffer failed: %d\n", result);
+        return false;
+    }
+
+    memset(&render_pass_info, 0, sizeof(VkRenderPassBeginInfo));
+    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    render_pass_info.renderPass = demo->render_pass;
+    render_pass_info.framebuffer = demo->framebuffers[image_index];
+    render_pass_info.renderArea.offset.x = 0;
+    render_pass_info.renderArea.offset.y = 0;
+    render_pass_info.renderArea.extent = demo->swap_chain_image_extent;
+    render_pass_info.clearValueCount = 1;
+    render_pass_info.pClearValues = &clear_color;
+
+    vkCmdBeginRenderPass(command_buffer, &render_pass_info,
+                         VK_SUBPASS_CONTENTS_INLINE);
+
+    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                      demo->pipeline);
+    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                            demo->pipeline_layout, 0, 1,
+                            &demo->descriptor_sets[image_index], 0, NULL);
+    vkCmdDraw(command_buffer, 3, 1, 0, 0);
+
+    vkCmdEndRenderPass(command_buffer);
+
+    result = vkEndCommandBuffer(command_buffer);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkEndCommandBuffer failed: %d\n", result);
+        return false;
+    }
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.waitSemaphoreCount = 1;
+    submit_info.pWaitSemaphores = &wait_semaphore;
+    submit_info.pWaitDstStageMask = &wait_stage;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &demo->command_buffers[image_index];
+    submit_info.signalSemaphoreCount = 1;
+    submit_info.pSignalSemaphores = &demo->render_finished;
+
+    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info,
+                           demo->render_fence);
+
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkQueueSubmit failed: %d\n", result);
+        return false;
+    }
+
+    memset(&present_info, 0, sizeof(VkPresentInfoKHR));
+    present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+    present_info.waitSemaphoreCount = 1;
+    present_info.pWaitSemaphores = &demo->render_finished;
+    present_info.swapchainCount = 1;
+    present_info.pSwapchains = &demo->swap_chain;
+    present_info.pImageIndices = &image_index;
+
+    result = vkQueuePresentKHR(demo->present_queue, &present_info);
+
+    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
+        if (!recreate_swap_chain(demo)) {
+            fprintf(stderr, "failed to recreate swap chain!\n");
+        }
+    } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
+        fprintf(stderr, "vkQueuePresentKHR failed: %d\n", result);
+        return false;
+    }
+    return true;
+}
+
+VkResult
+destroy_debug_utils_messenger_ext(VkInstance instance,
+                                  VkDebugUtilsMessengerEXT debugMessenger,
+                                  const VkAllocationCallbacks *pAllocator) {
+    PFN_vkDestroyDebugUtilsMessengerEXT func =
+        (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
+            instance, "vkDestroyDebugUtilsMessengerEXT");
+    if (func != NULL) {
+        func(instance, debugMessenger, pAllocator);
+        return VK_SUCCESS;
+    } else {
+        return VK_ERROR_EXTENSION_NOT_PRESENT;
+    }
+}
+
+bool cleanup(struct vulkan_demo *demo) {
+    VkResult result;
+
+    printf("cleaning up\n");
+    result = vkDeviceWaitIdle(demo->device);
+    if (result != VK_SUCCESS) {
+        fprintf(stderr, "vkDeviceWaitIdle failed: %d\n", result);
+        return false;
+    }
+
+    destroy_swap_chain_related_resources(demo);
+
+    vkFreeCommandBuffers(demo->device, demo->command_pool,
+                         demo->swap_chain_images_len, demo->command_buffers);
+    vkDestroyCommandPool(demo->device, demo->command_pool, NULL);
+    vkDestroySampler(demo->device, demo->sampler, NULL);
+    vkDestroySemaphore(demo->device, demo->render_finished, NULL);
+    vkDestroySemaphore(demo->device, demo->image_available, NULL);
+    vkDestroyFence(demo->device, demo->render_fence, NULL);
+
+    vkDestroyImage(demo->device, demo->demo_texture_image, NULL);
+    vkDestroyImageView(demo->device, demo->demo_texture_image_view, NULL);
+    vkFreeMemory(demo->device, demo->demo_texture_memory, NULL);
+
+    vkDestroyDescriptorSetLayout(demo->device, demo->descriptor_set_layout,
+                                 NULL);
+    vkDestroyDescriptorPool(demo->device, demo->descriptor_pool, NULL);
+
+    vkDestroyDevice(demo->device, NULL);
+    vkDestroySurfaceKHR(demo->instance, demo->surface, NULL);
+
+    if (demo->debug_messenger) {
+        result = destroy_debug_utils_messenger_ext(demo->instance,
+                                                   demo->debug_messenger, NULL);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "Couldn't destroy debug messenger: %d\n", result);
+            return false;
+        }
+    }
+    vkDestroyInstance(demo->instance, NULL);
+    if (demo->swap_chain_images) {
+        free(demo->swap_chain_images);
+    }
+    if (demo->swap_chain_image_views) {
+        free(demo->swap_chain_image_views);
+    }
+
+    if (demo->overlay_images) {
+        free(demo->overlay_images);
+    }
+    if (demo->overlay_image_views) {
+        free(demo->overlay_image_views);
+    }
+    if (demo->overlay_image_memories) {
+        free(demo->overlay_image_memories);
+    }
+
+    if (demo->descriptor_sets) {
+        free(demo->descriptor_sets);
+    }
+    if (demo->framebuffers) {
+        free(demo->framebuffers);
+    }
+    if (demo->command_buffers) {
+        free(demo->command_buffers);
+    }
+
+    SDL_DestroyWindow(demo->win);
+
+    return true;
+}
+
+int main(void) {
+    struct vulkan_demo demo;
+    struct nk_context *ctx;
+    struct nk_colorf bg;
+    struct nk_image img;
+    uint32_t image_index;
+    VkResult result;
+    VkSemaphore nk_semaphore;
+
+    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+        fprintf(stderr, "[SDL] failed to init!\n");
+        exit(1);
+    }
+
+    memset(&demo, 0, sizeof(struct vulkan_demo));
+    demo.win = SDL_CreateWindow(
+        "Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH,
+        WINDOW_HEIGHT,
+        SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
+
+    if (!create_vulkan_demo(&demo)) {
+        fprintf(stderr, "failed to create vulkan demo!\n");
+        exit(1);
+    }
+    ctx = nk_sdl_init(demo.win, demo.device, demo.physical_device,
+                      demo.indices.graphics, demo.overlay_image_views,
+                      demo.swap_chain_images_len, demo.swap_chain_image_format,
+                      0, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+    /* 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_atlas *atlas;
+        nk_sdl_font_stash_begin(&atlas);
+        /*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_sdl_font_stash_end(demo.graphics_queue);
+        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+        /*nk_style_set_font(ctx, &droid->handle);*/
+    }
+
+    img = nk_image_ptr(demo.demo_texture_image_view);
+    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+    while (true) {
+        SDL_Event evt;
+
+        nk_input_begin(ctx);
+        while (SDL_PollEvent(&evt)) {
+            if (evt.type == SDL_QUIT)
+                goto cleanup;
+            if (evt.type == SDL_WINDOWEVENT &&
+                evt.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
+                recreate_swap_chain(&demo);
+            nk_sdl_handle_event(&evt);
+        }
+        nk_sdl_handle_grab(); /* optional grabbing behavior */
+        nk_input_end(ctx);
+
+        /* 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"))
+                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, 25, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 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);
+
+        /* Bindless Texture */
+        if (nk_begin(ctx, "Texture", nk_rect(500, 300, 200, 200),
+                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
+                         NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {
+            struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
+            struct nk_rect total_space = nk_window_get_content_region(ctx);
+            nk_draw_image(canvas, total_space, &img, nk_white);
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+#ifdef INCLUDE_CALCULATOR
+        calculator(ctx);
+#endif
+#ifdef INCLUDE_CANVAS
+        canvas(ctx);
+#endif
+#ifdef INCLUDE_OVERVIEW
+        overview(ctx);
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+        node_editor(ctx);
+#endif
+        /* ----------------------------------------- */
+
+        result = vkWaitForFences(demo.device, 1, &demo.render_fence, VK_TRUE,
+                                 UINT64_MAX);
+
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkWaitForFences failed: %d\n", result);
+            return false;
+        }
+
+        result = vkResetFences(demo.device, 1, &demo.render_fence);
+        if (result != VK_SUCCESS) {
+            fprintf(stderr, "vkResetFences failed: %d\n", result);
+            return false;
+        }
+
+        result =
+            vkAcquireNextImageKHR(demo.device, demo.swap_chain, UINT64_MAX,
+                                  demo.image_available, NULL, &image_index);
+
+        if (result == VK_ERROR_OUT_OF_DATE_KHR) {
+            recreate_swap_chain(&demo);
+
+            /* If vkAcquireNextImageKHR does not successfully acquire an image,
+             * semaphore and fence are unaffected. */
+            continue;
+        }
+        if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
+            fprintf(stderr, "vkAcquireNextImageKHR failed: %d\n", result);
+            return false;
+        }
+
+        /* Draw */
+        nk_semaphore = nk_sdl_render(demo.graphics_queue, image_index,
+                                     demo.image_available, NK_ANTI_ALIASING_ON);
+        if (!render(&demo, &bg, nk_semaphore, image_index)) {
+            fprintf(stderr, "render failed\n");
+            return false;
+        }
+    }
+cleanup:
+    nk_sdl_shutdown();
+    cleanup(&demo);
+    SDL_Quit();
+    return 0;
+}

+ 1648 - 0
demo/sdl_vulkan/nuklear_sdl_vulkan.h

@@ -0,0 +1,1648 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warranty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_VULKAN_H_
+#define NK_SDL_VULKAN_H_
+
+unsigned char nuklearshaders_nuklear_vert_spv[] = {
+  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,
+  0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+  0x2a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,
+  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,
+  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,
+  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,
+  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,
+  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,
+  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
+  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,
+  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
+  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,
+  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
+  0x69, 0x6f, 0x6e, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65,
+  0x72, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x06, 0x00, 0x06, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a,
+  0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x16, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f,
+  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00,
+  0x66, 0x72, 0x61, 0x67, 0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
+  0x43, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
+  0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x20, 0x00, 0x04, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x15, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x7f, 0x43, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00,
+  0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
+  0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,
+  0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+  0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+  0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+  0x19, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+  0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
+  0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
+  0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
+  0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+  0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x22, 0x00, 0x00, 0x00,
+  0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00,
+  0x25, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x2d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
+  0x2d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+  0x32, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x37, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x37, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x3c, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,
+  0x3c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x40, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
+  0x3a, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
+  0x27, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
+  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
+};
+unsigned int nuklearshaders_nuklear_vert_spv_len = 1856;
+unsigned char nuklearshaders_nuklear_frag_spv[] = {
+  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,
+  0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,
+  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,
+  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,
+  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,
+  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,
+  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,
+  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
+  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,
+  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
+  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,
+  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x72,
+  0x65, 0x6e, 0x74, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00,
+  0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,
+  0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,
+  0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,
+  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
+  0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
+  0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,
+  0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
+  0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+  0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+  0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+  0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+  0x09, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
+  0x3e, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
+  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
+};
+unsigned int nuklearshaders_nuklear_frag_spv_len = 860;
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <SDL2/SDL.h>
+
+enum nk_sdl_init_state { NK_SDL_DEFAULT = 0 };
+
+NK_API struct nk_context *
+nk_sdl_init(SDL_Window *win, VkDevice logical_device,
+            VkPhysicalDevice physical_device,
+            uint32_t graphics_queue_family_index, VkImageView *image_views,
+            uint32_t image_views_len, VkFormat color_format,
+            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,
+            VkDeviceSize max_element_buffer);
+NK_API void nk_sdl_shutdown(void);
+NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_sdl_font_stash_end(VkQueue graphics_queue);
+NK_API int nk_sdl_handle_event(SDL_Event *evt);
+NK_API VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,
+                                 VkSemaphore wait_semaphore,
+                                 enum nk_anti_aliasing AA);
+NK_API void nk_sdl_resize(uint32_t framebuffer_width,
+                          uint32_t framebuffer_height);
+NK_API void nk_sdl_device_destroy(void);
+NK_API void
+nk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,
+                     uint32_t graphics_queue_family_index,
+                     VkImageView *image_views, uint32_t image_views_len,
+                     VkFormat color_format, VkDeviceSize max_vertex_buffer,
+                     VkDeviceSize max_element_buffer,
+                     uint32_t framebuffer_width, uint32_t framebuffer_height);
+NK_API void nk_sdl_handle_grab(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_VULKAN_IMPLEMENTATION
+#undef NK_SDL_VULKAN_IMPLEMENTATION
+#include <stdlib.h>
+
+#ifndef NK_SDL_TEXT_MAX
+#define NK_SDL_TEXT_MAX 256
+#endif
+#ifndef NK_SDL_MAX_TEXTURES
+#define NK_SDL_MAX_TEXTURES 256
+#endif
+#ifndef NK_SDL_MAX_KEYS
+#define NK_SDL_MAX_KEYS 32
+#endif
+
+#define VK_COLOR_COMPONENT_MASK_RGBA                                           \
+    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \
+        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+
+struct nk_sdl_vertex {
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+
+struct nk_vulkan_texture_descriptor_set {
+    VkImageView image_view;
+    VkDescriptorSet descriptor_set;
+};
+
+struct nk_sdl_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture tex_null;
+    int max_vertex_buffer;
+    int max_element_buffer;
+    VkDevice logical_device;
+    VkPhysicalDevice physical_device;
+    VkImageView *image_views;
+    uint32_t image_views_len;
+    VkFormat color_format;
+    VkFramebuffer *framebuffers;
+    uint32_t framebuffers_len;
+    VkCommandBuffer *command_buffers;
+    uint32_t command_buffers_len;
+    VkSampler sampler;
+    VkCommandPool command_pool;
+    VkSemaphore render_completed;
+    VkBuffer vertex_buffer;
+    VkDeviceMemory vertex_memory;
+    void *mapped_vertex;
+    VkBuffer index_buffer;
+    VkDeviceMemory index_memory;
+    void *mapped_index;
+    VkBuffer uniform_buffer;
+    VkDeviceMemory uniform_memory;
+    void *mapped_uniform;
+    VkRenderPass render_pass;
+    VkDescriptorPool descriptor_pool;
+    VkDescriptorSetLayout uniform_descriptor_set_layout;
+    VkDescriptorSet uniform_descriptor_set;
+    VkDescriptorSetLayout texture_descriptor_set_layout;
+    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;
+    uint32_t texture_descriptor_sets_len;
+    VkPipelineLayout pipeline_layout;
+    VkPipeline pipeline;
+    VkImage font_image;
+    VkImageView font_image_view;
+    VkDeviceMemory font_memory;
+};
+
+static struct nk_sdl {
+    SDL_Window *win;
+    int width, height;
+    int display_width, display_height;
+    struct nk_sdl_device vulkan;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    unsigned int text[NK_SDL_TEXT_MAX];
+    int text_len;
+    struct nk_vec2 scroll;
+    uint64_t delta_time_milliseconds_last;
+} sdl;
+
+struct Mat4f {
+    float m[16];
+};
+
+NK_INTERN uint32_t nk_sdl_find_memory_index(VkPhysicalDevice physical_device,
+                                            uint32_t type_filter,
+                                            VkMemoryPropertyFlags properties) {
+    VkPhysicalDeviceMemoryProperties mem_properties;
+    uint32_t i;
+
+    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);
+    for (i = 0; i < mem_properties.memoryTypeCount; i++) {
+        if ((type_filter & (1 << i)) &&
+            (mem_properties.memoryTypes[i].propertyFlags & properties) ==
+                properties) {
+            return i;
+        }
+    }
+
+    assert(0);
+    return 0;
+}
+
+NK_INTERN void nk_sdl_create_sampler(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkSamplerCreateInfo sampler_info;
+    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));
+
+    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+    sampler_info.pNext = NULL;
+    sampler_info.maxAnisotropy = 1.0;
+    sampler_info.magFilter = VK_FILTER_LINEAR;
+    sampler_info.minFilter = VK_FILTER_LINEAR;
+    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.mipLodBias = 0.0f;
+    sampler_info.compareEnable = VK_FALSE;
+    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
+    sampler_info.minLod = 0.0f;
+    sampler_info.maxLod = 0.0f;
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+
+    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,
+                             &dev->sampler);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_command_pool(struct nk_sdl_device *dev,
+                           uint32_t graphics_queue_family_index) {
+    VkResult result;
+    VkCommandPoolCreateInfo pool_info;
+    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));
+
+    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_info.queueFamilyIndex = graphics_queue_family_index;
+    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,
+                                 &dev->command_pool);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_command_buffers(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkCommandBufferAllocateInfo allocate_info;
+    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));
+
+    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *
+                                                     sizeof(VkCommandBuffer));
+    dev->command_buffers_len = dev->image_views_len;
+
+    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    allocate_info.commandPool = dev->command_pool;
+    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    allocate_info.commandBufferCount = dev->command_buffers_len;
+
+    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,
+                                      dev->command_buffers);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_semaphore(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkSemaphoreCreateInfo semaphore_info;
+    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));
+
+    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,
+                                &dev->render_completed));
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_buffer_and_memory(struct nk_sdl_device *dev,
+                                               VkBuffer *buffer,
+                                               VkBufferUsageFlags usage,
+                                               VkDeviceMemory *memory,
+                                               VkDeviceSize size) {
+    VkMemoryRequirements mem_reqs;
+    VkResult result;
+    VkBufferCreateInfo buffer_info;
+    VkMemoryAllocateInfo alloc_info;
+
+    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.size = size;
+    buffer_info.usage = usage;
+    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_render_pass(struct nk_sdl_device *dev) {
+    VkAttachmentDescription attachment;
+    VkAttachmentReference color_reference;
+    VkSubpassDependency subpass_dependency;
+    VkSubpassDescription subpass_description;
+    VkRenderPassCreateInfo render_pass_info;
+    VkResult result;
+
+    memset(&attachment, 0, sizeof(VkAttachmentDescription));
+    attachment.format = dev->color_format;
+    attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    memset(&color_reference, 0, sizeof(VkAttachmentReference));
+    color_reference.attachment = 0;
+    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));
+    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+    subpass_dependency.srcAccessMask = 0;
+    subpass_dependency.srcStageMask =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    subpass_dependency.dstSubpass = 0;
+    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    subpass_dependency.dstStageMask =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+
+    memset(&subpass_description, 0, sizeof(VkSubpassDescription));
+    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    subpass_description.colorAttachmentCount = 1;
+    subpass_description.pColorAttachments = &color_reference;
+
+    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));
+    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    render_pass_info.attachmentCount = 1;
+    render_pass_info.pAttachments = &attachment;
+    render_pass_info.subpassCount = 1;
+    render_pass_info.pSubpasses = &subpass_description;
+    render_pass_info.dependencyCount = 1;
+    render_pass_info.pDependencies = &subpass_dependency;
+
+    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,
+                                &dev->render_pass);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_framebuffers(struct nk_sdl_device *dev,
+                                          uint32_t framebuffer_width,
+                                          uint32_t framebuffer_height) {
+
+    VkFramebufferCreateInfo framebuffer_create_info;
+    uint32_t i;
+    VkResult result;
+
+    dev->framebuffers =
+        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));
+
+    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));
+    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    framebuffer_create_info.renderPass = dev->render_pass;
+    framebuffer_create_info.attachmentCount = 1;
+    framebuffer_create_info.width = framebuffer_width;
+    framebuffer_create_info.height = framebuffer_height;
+    framebuffer_create_info.layers = 1;
+    for (i = 0; i < dev->image_views_len; i++) {
+        framebuffer_create_info.pAttachments = &dev->image_views[i];
+        result =
+            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,
+                                NULL, &dev->framebuffers[i]);
+        NK_ASSERT(result == VK_SUCCESS);
+    }
+    dev->framebuffers_len = dev->image_views_len;
+}
+
+NK_INTERN void nk_sdl_create_descriptor_pool(struct nk_sdl_device *dev) {
+    VkDescriptorPoolSize pool_sizes[2];
+    VkDescriptorPoolCreateInfo pool_info;
+    VkResult result;
+
+    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);
+    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    pool_sizes[0].descriptorCount = 1;
+    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    pool_sizes[1].descriptorCount = NK_SDL_MAX_TEXTURES;
+
+    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));
+    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    pool_info.poolSizeCount = 2;
+    pool_info.pPoolSizes = pool_sizes;
+    pool_info.maxSets = 1 + NK_SDL_MAX_TEXTURES;
+
+    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,
+                                    &dev->descriptor_pool);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_uniform_descriptor_set_layout(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayoutBinding binding;
+    VkDescriptorSetLayoutCreateInfo descriptor_set_info;
+    VkResult result;
+
+    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));
+    binding.binding = 0;
+    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    binding.descriptorCount = 1;
+    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+
+    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+    descriptor_set_info.sType =
+        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_set_info.bindingCount = 1;
+    descriptor_set_info.pBindings = &binding;
+
+    result =
+        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,
+                                    NULL, &dev->uniform_descriptor_set_layout);
+
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_and_update_uniform_descriptor_set(struct nk_sdl_device *dev) {
+    VkDescriptorSetAllocateInfo allocate_info;
+    VkDescriptorBufferInfo buffer_info;
+    VkWriteDescriptorSet descriptor_write;
+    VkResult result;
+
+    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));
+    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    allocate_info.descriptorPool = dev->descriptor_pool;
+    allocate_info.descriptorSetCount = 1;
+    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;
+
+    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,
+                                      &dev->uniform_descriptor_set);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));
+    buffer_info.buffer = dev->uniform_buffer;
+    buffer_info.offset = 0;
+    buffer_info.range = sizeof(struct Mat4f);
+
+    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = dev->uniform_descriptor_set;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.dstArrayElement = 0;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.pBufferInfo = &buffer_info;
+
+    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+NK_INTERN void
+nk_sdl_create_texture_descriptor_set_layout(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayoutBinding binding;
+    VkDescriptorSetLayoutCreateInfo descriptor_set_info;
+    VkResult result;
+
+    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));
+    binding.binding = 0;
+    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    binding.descriptorCount = 1;
+    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+
+    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+    descriptor_set_info.sType =
+        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_set_info.bindingCount = 1;
+    descriptor_set_info.pBindings = &binding;
+
+    result =
+        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,
+                                    NULL, &dev->texture_descriptor_set_layout);
+
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_texture_descriptor_sets(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayout *descriptor_set_layouts;
+    VkDescriptorSet *descriptor_sets;
+    VkDescriptorSetAllocateInfo allocate_info;
+    VkResult result;
+    int i;
+
+    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(
+        NK_SDL_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));
+    descriptor_sets = (VkDescriptorSet *)malloc(NK_SDL_MAX_TEXTURES *
+                                                sizeof(VkDescriptorSet));
+
+    dev->texture_descriptor_sets =
+        (struct nk_vulkan_texture_descriptor_set *)malloc(
+            NK_SDL_MAX_TEXTURES *
+            sizeof(struct nk_vulkan_texture_descriptor_set));
+    dev->texture_descriptor_sets_len = 0;
+
+    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {
+        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;
+        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;
+    }
+
+    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));
+    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    allocate_info.descriptorPool = dev->descriptor_pool;
+    allocate_info.descriptorSetCount = NK_SDL_MAX_TEXTURES;
+    allocate_info.pSetLayouts = descriptor_set_layouts;
+
+    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,
+                                      descriptor_sets);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {
+        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];
+    }
+    free(descriptor_set_layouts);
+    free(descriptor_sets);
+}
+
+NK_INTERN void nk_sdl_create_pipeline_layout(struct nk_sdl_device *dev) {
+    VkPipelineLayoutCreateInfo pipeline_layout_info;
+    VkDescriptorSetLayout descriptor_set_layouts[2];
+    VkResult result;
+
+    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;
+    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;
+
+    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));
+    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipeline_layout_info.setLayoutCount = 2;
+    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;
+
+    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,
+                                     NULL, &dev->pipeline_layout));
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN VkPipelineShaderStageCreateInfo
+nk_sdl_create_shader(struct nk_sdl_device *dev, unsigned char *spv_shader,
+                     uint32_t size, VkShaderStageFlagBits stage_bit) {
+    VkShaderModuleCreateInfo create_info;
+    VkPipelineShaderStageCreateInfo shader_info;
+    VkShaderModule module = NULL;
+    VkResult result;
+
+    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    create_info.codeSize = size;
+    create_info.pCode = (const uint32_t *)spv_shader;
+    result =
+        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
+    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    shader_info.stage = stage_bit;
+    shader_info.module = module;
+    shader_info.pName = "main";
+    return shader_info;
+}
+
+NK_INTERN void nk_sdl_create_pipeline(struct nk_sdl_device *dev) {
+    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;
+    VkPipelineRasterizationStateCreateInfo rasterization_state;
+    VkPipelineColorBlendAttachmentState attachment_state = {
+        VK_TRUE,
+        VK_BLEND_FACTOR_SRC_ALPHA,
+        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        VK_BLEND_OP_ADD,
+        VK_BLEND_FACTOR_SRC_ALPHA,
+        VK_BLEND_FACTOR_ONE,
+        VK_BLEND_OP_ADD,
+        VK_COLOR_COMPONENT_MASK_RGBA,
+    };
+    VkPipelineColorBlendStateCreateInfo color_blend_state;
+    VkPipelineViewportStateCreateInfo viewport_state;
+    VkPipelineMultisampleStateCreateInfo multisample_state;
+    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,
+                                        VK_DYNAMIC_STATE_SCISSOR};
+    VkPipelineDynamicStateCreateInfo dynamic_state;
+    VkPipelineShaderStageCreateInfo shader_stages[2];
+    VkVertexInputBindingDescription vertex_input_info;
+    VkVertexInputAttributeDescription vertex_attribute_description[3];
+    VkPipelineVertexInputStateCreateInfo vertex_input;
+    VkGraphicsPipelineCreateInfo pipeline_info;
+    VkResult result;
+
+    memset(&input_assembly_state, 0,
+           sizeof(VkPipelineInputAssemblyStateCreateInfo));
+    input_assembly_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+    input_assembly_state.primitiveRestartEnable = VK_FALSE;
+
+    memset(&rasterization_state, 0,
+           sizeof(VkPipelineRasterizationStateCreateInfo));
+    rasterization_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
+    rasterization_state.cullMode = VK_CULL_MODE_NONE;
+    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+    rasterization_state.lineWidth = 1.0f;
+
+    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));
+    color_blend_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+    color_blend_state.attachmentCount = 1;
+    color_blend_state.pAttachments = &attachment_state;
+
+    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));
+    viewport_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+    viewport_state.viewportCount = 1;
+    viewport_state.scissorCount = 1;
+
+    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));
+    multisample_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));
+    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+    dynamic_state.pDynamicStates = dynamic_states;
+    dynamic_state.dynamicStateCount = 2;
+
+    shader_stages[0] = nk_sdl_create_shader(
+        dev, nuklearshaders_nuklear_vert_spv,
+        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);
+    shader_stages[1] = nk_sdl_create_shader(
+        dev, nuklearshaders_nuklear_frag_spv,
+        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);
+
+    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));
+    vertex_input_info.binding = 0;
+    vertex_input_info.stride = sizeof(struct nk_sdl_vertex);
+    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+    memset(&vertex_attribute_description, 0,
+           sizeof(VkVertexInputAttributeDescription) * 3);
+    vertex_attribute_description[0].location = 0;
+    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;
+    vertex_attribute_description[0].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, position);
+    vertex_attribute_description[1].location = 1;
+    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;
+    vertex_attribute_description[1].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, uv);
+    vertex_attribute_description[2].location = 2;
+    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;
+    vertex_attribute_description[2].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, col);
+
+    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));
+    vertex_input.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+    vertex_input.vertexBindingDescriptionCount = 1;
+    vertex_input.pVertexBindingDescriptions = &vertex_input_info;
+    vertex_input.vertexAttributeDescriptionCount = 3;
+    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;
+
+    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));
+    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+    pipeline_info.flags = 0;
+    pipeline_info.stageCount = 2;
+    pipeline_info.pStages = shader_stages;
+    pipeline_info.pVertexInputState = &vertex_input;
+    pipeline_info.pInputAssemblyState = &input_assembly_state;
+    pipeline_info.pViewportState = &viewport_state;
+    pipeline_info.pRasterizationState = &rasterization_state;
+    pipeline_info.pMultisampleState = &multisample_state;
+    pipeline_info.pColorBlendState = &color_blend_state;
+    pipeline_info.pDynamicState = &dynamic_state;
+    pipeline_info.layout = dev->pipeline_layout;
+    pipeline_info.renderPass = dev->render_pass;
+    pipeline_info.basePipelineIndex = -1;
+    pipeline_info.basePipelineHandle = NULL;
+
+    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,
+                                       &pipeline_info, NULL, &dev->pipeline);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);
+    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);
+}
+
+NK_INTERN void nk_sdl_create_render_resources(struct nk_sdl_device *dev,
+                                              uint32_t framebuffer_width,
+                                              uint32_t framebuffer_height) {
+    nk_sdl_create_render_pass(dev);
+    nk_sdl_create_framebuffers(dev, framebuffer_width, framebuffer_height);
+    nk_sdl_create_descriptor_pool(dev);
+    nk_sdl_create_uniform_descriptor_set_layout(dev);
+    nk_sdl_create_and_update_uniform_descriptor_set(dev);
+    nk_sdl_create_texture_descriptor_set_layout(dev);
+    nk_sdl_create_texture_descriptor_sets(dev);
+    nk_sdl_create_pipeline_layout(dev);
+    nk_sdl_create_pipeline(dev);
+}
+
+NK_API void
+nk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,
+                     uint32_t graphics_queue_family_index,
+                     VkImageView *image_views, uint32_t image_views_len,
+                     VkFormat color_format, VkDeviceSize max_vertex_buffer,
+                     VkDeviceSize max_element_buffer,
+                     uint32_t framebuffer_width, uint32_t framebuffer_height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+    dev->max_vertex_buffer = max_vertex_buffer;
+    dev->max_element_buffer = max_element_buffer;
+    nk_buffer_init_default(&dev->cmds);
+    dev->logical_device = logical_device;
+    dev->physical_device = physical_device;
+    dev->image_views = image_views;
+    dev->image_views_len = image_views_len;
+    dev->color_format = color_format;
+    dev->framebuffers = NULL;
+    dev->framebuffers_len = 0;
+
+    nk_sdl_create_sampler(dev);
+    nk_sdl_create_command_pool(dev, graphics_queue_family_index);
+    nk_sdl_create_command_buffers(dev);
+    nk_sdl_create_semaphore(dev);
+
+    nk_sdl_create_buffer_and_memory(dev, &dev->vertex_buffer,
+                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+                                    &dev->vertex_memory, max_vertex_buffer);
+    nk_sdl_create_buffer_and_memory(dev, &dev->index_buffer,
+                                    VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
+                                    &dev->index_memory, max_element_buffer);
+    nk_sdl_create_buffer_and_memory(dev, &dev->uniform_buffer,
+                                    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+                                    &dev->uniform_memory, sizeof(struct Mat4f));
+
+    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,
+                0, &dev->mapped_vertex);
+    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,
+                0, &dev->mapped_index);
+    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,
+                sizeof(struct Mat4f), 0, &dev->mapped_uniform);
+
+    nk_sdl_create_render_resources(dev, framebuffer_width, framebuffer_height);
+}
+
+NK_INTERN void nk_sdl_device_upload_atlas(VkQueue graphics_queue,
+                                          const void *image, int width,
+                                          int height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    VkImageCreateInfo image_info;
+    VkResult result;
+    VkMemoryRequirements mem_reqs;
+    VkMemoryAllocateInfo alloc_info;
+    VkBufferCreateInfo buffer_info;
+    uint8_t *data = 0;
+    VkCommandBufferBeginInfo begin_info;
+    VkCommandBuffer command_buffer;
+    VkImageMemoryBarrier image_memory_barrier;
+    VkBufferImageCopy buffer_copy_region;
+    VkImageMemoryBarrier image_shader_memory_barrier;
+    VkFence fence;
+    VkFenceCreateInfo fence_create;
+    VkSubmitInfo submit_info;
+    VkImageViewCreateInfo image_view_info;
+    struct {
+        VkDeviceMemory memory;
+        VkBuffer buffer;
+    } staging_buffer;
+
+    memset(&image_info, 0, sizeof(VkImageCreateInfo));
+    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_info.imageType = VK_IMAGE_TYPE_2D;
+    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
+    image_info.extent.width = (uint32_t)width;
+    image_info.extent.height = (uint32_t)height;
+    image_info.extent.depth = 1;
+    image_info.mipLevels = 1;
+    image_info.arrayLayers = 1;
+    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
+    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    image_info.usage =
+        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+    result =
+        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,
+                                 &mem_reqs);
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,
+                              &dev->font_memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindImageMemory(dev->logical_device, dev->font_image,
+                               dev->font_memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.size = alloc_info.allocationSize;
+    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,
+                            &staging_buffer.buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,
+                                  &mem_reqs);
+
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,
+                              &staging_buffer.memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,
+                                staging_buffer.memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,
+                         alloc_info.allocationSize, 0, (void **)&data);
+    NK_ASSERT(result == VK_SUCCESS);
+    memcpy(data, image, width * height * 4);
+    vkUnmapMemory(dev->logical_device, staging_buffer.memory);
+
+    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    NK_ASSERT(dev->command_buffers_len > 0);
+    /*
+    use the same command buffer as for render as we are regenerating the
+    buffer during render anyway
+    */
+    command_buffer = dev->command_buffers[0];
+    result = vkBeginCommandBuffer(command_buffer, &begin_info);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_memory_barrier.image = dev->font_image;
+    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_memory_barrier.subresourceRange.levelCount = 1;
+    image_memory_barrier.subresourceRange.layerCount = 1;
+    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
+                         &image_memory_barrier);
+
+    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));
+    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    buffer_copy_region.imageSubresource.layerCount = 1;
+    buffer_copy_region.imageExtent.width = (uint32_t)width;
+    buffer_copy_region.imageExtent.height = (uint32_t)height;
+    buffer_copy_region.imageExtent.depth = 1;
+
+    vkCmdCopyBufferToImage(
+        command_buffer, staging_buffer.buffer, dev->font_image,
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);
+
+    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_shader_memory_barrier.image = dev->font_image;
+    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.oldLayout =
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_shader_memory_barrier.newLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    image_shader_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_shader_memory_barrier.subresourceRange.levelCount = 1;
+    image_shader_memory_barrier.subresourceRange.layerCount = 1;
+    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,
+                         NULL, 1, &image_shader_memory_barrier);
+
+    result = vkEndCommandBuffer(command_buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));
+    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+
+    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+
+    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);
+    NK_ASSERT(result == VK_SUCCESS);
+    result =
+        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkDestroyFence(dev->logical_device, fence, NULL);
+
+    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);
+    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);
+
+    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));
+    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    image_view_info.image = dev->font_image;
+    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    image_view_info.format = image_info.format;
+    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    image_view_info.subresourceRange.layerCount = 1;
+    image_view_info.subresourceRange.levelCount = 1;
+
+    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,
+                               &dev->font_image_view);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_destroy_render_resources(struct nk_sdl_device *dev) {
+    uint32_t i;
+
+    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);
+    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);
+    vkDestroyDescriptorSetLayout(dev->logical_device,
+                                 dev->texture_descriptor_set_layout, NULL);
+    vkDestroyDescriptorSetLayout(dev->logical_device,
+                                 dev->uniform_descriptor_set_layout, NULL);
+    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);
+    for (i = 0; i < dev->framebuffers_len; i++) {
+        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);
+    }
+    free(dev->framebuffers);
+    dev->framebuffers_len = 0;
+    free(dev->texture_descriptor_sets);
+    dev->texture_descriptor_sets_len = 0;
+    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);
+}
+
+NK_API void nk_sdl_resize(uint32_t framebuffer_width,
+                          uint32_t framebuffer_height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    SDL_GetWindowSize(sdl.win, &sdl.width, &sdl.height);
+    sdl.display_width = framebuffer_width;
+    sdl.display_height = framebuffer_height;
+
+    nk_sdl_destroy_render_resources(dev);
+    nk_sdl_create_render_resources(dev, sdl.display_width, sdl.display_height);
+}
+
+NK_API void nk_sdl_device_destroy(void) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    vkDeviceWaitIdle(dev->logical_device);
+
+    nk_sdl_destroy_render_resources(dev);
+
+    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,
+                         dev->command_buffers_len, dev->command_buffers);
+    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);
+    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);
+
+    vkUnmapMemory(dev->logical_device, dev->vertex_memory);
+    vkUnmapMemory(dev->logical_device, dev->index_memory);
+    vkUnmapMemory(dev->logical_device, dev->uniform_memory);
+
+    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);
+    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);
+    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);
+
+    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);
+    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);
+    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);
+
+    vkDestroySampler(dev->logical_device, dev->sampler, NULL);
+
+    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);
+    vkDestroyImage(dev->logical_device, dev->font_image, NULL);
+    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);
+
+    free(dev->command_buffers);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_API
+void nk_sdl_shutdown(void) {
+    nk_font_atlas_clear(&sdl.atlas);
+    nk_free(&sdl.ctx);
+    nk_sdl_device_destroy();
+    memset(&sdl, 0, sizeof(sdl));
+}
+
+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(VkQueue graphics_queue) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    const void *image;
+    int w, h;
+    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sdl_device_upload_atlas(graphics_queue, image, w, h);
+    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(dev->font_image_view),
+                      &dev->tex_null);
+    if (sdl.atlas.default_font) {
+        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+    }
+}
+
+NK_API void nk_sdl_handle_grab(void) {
+    struct nk_context *ctx = &sdl.ctx;
+    if (ctx->input.mouse.grab) {
+        SDL_SetRelativeMouseMode(SDL_TRUE);
+    } else if (ctx->input.mouse.ungrab) {
+        /* better support for older SDL by setting mode first; causes an extra
+         * mouse motion event */
+        SDL_SetRelativeMouseMode(SDL_FALSE);
+        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x,
+                              (int)ctx->input.mouse.prev.y);
+    } else if (ctx->input.mouse.grabbed) {
+        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+    }
+}
+
+NK_API int nk_sdl_handle_event(SDL_Event *evt) {
+    struct nk_context *ctx = &sdl.ctx;
+
+    switch (evt->type) {
+    case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */
+    case SDL_KEYDOWN: {
+        int down = evt->type == SDL_KEYDOWN;
+        const Uint8 *state = SDL_GetKeyboardState(0);
+        switch (evt->key.keysym.sym) {
+        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_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same
+                               routine */
+    case SDL_MOUSEBUTTONDOWN: {
+        int down = evt->type == SDL_MOUSEBUTTONDOWN;
+        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_MOUSEMOTION: {
+        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_TEXTINPUT: {
+        nk_glyph glyph;
+        memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+        nk_input_glyph(ctx, glyph);
+        return 1;
+    }
+
+    case SDL_MOUSEWHEEL:
+        nk_input_scroll(ctx, nk_vec2((float)evt->wheel.x, (float)evt->wheel.y));
+        return 1;
+    }
+    return 0;
+}
+
+NK_INTERN void update_texture_descriptor_set(
+    struct nk_sdl_device *dev,
+    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,
+    VkImageView image_view) {
+    VkDescriptorImageInfo descriptor_image_info;
+    VkWriteDescriptorSet descriptor_write;
+
+    texture_descriptor_set->image_view = image_view;
+
+    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));
+    descriptor_image_info.sampler = dev->sampler;
+    descriptor_image_info.imageView = texture_descriptor_set->image_view;
+    descriptor_image_info.imageLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.dstArrayElement = 0;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.pImageInfo = &descriptor_image_info;
+
+    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+NK_API
+VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,
+                          VkSemaphore wait_semaphore,
+                          enum nk_anti_aliasing AA) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+    struct nk_buffer vbuf, ebuf;
+
+    struct Mat4f projection = {
+        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
+         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},
+    };
+
+    VkCommandBufferBeginInfo begin_info;
+    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};
+    VkRenderPassBeginInfo render_pass_begin_nfo;
+    VkCommandBuffer command_buffer;
+    VkResult result;
+    VkViewport viewport;
+
+    VkDeviceSize doffset = 0;
+    VkImageView current_texture = NULL;
+    uint32_t index_offset = 0;
+    VkRect2D scissor;
+    uint32_t wait_semaphore_count;
+    VkSemaphore *wait_semaphores;
+    VkPipelineStageFlags wait_stage =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkSubmitInfo submit_info;
+    uint64_t time_now;
+
+    time_now = SDL_GetTicks64();
+    sdl.ctx.delta_time_seconds =
+        (float)(time_now - sdl.delta_time_milliseconds_last) / 1000.0f;
+    sdl.delta_time_milliseconds_last = time_now;
+
+    projection.m[0] /= sdl.display_width;
+    projection.m[5] /= sdl.display_height;
+
+    memcpy(dev->mapped_uniform, &projection, sizeof(projection));
+
+    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));
+    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    render_pass_begin_nfo.renderPass = dev->render_pass;
+    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)sdl.display_width;
+    render_pass_begin_nfo.renderArea.extent.height =
+        (uint32_t)sdl.display_height;
+    render_pass_begin_nfo.clearValueCount = 1;
+    render_pass_begin_nfo.pClearValues = &clear_value;
+    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];
+
+    command_buffer = dev->command_buffers[buffer_index];
+
+    result = vkBeginCommandBuffer(command_buffer, &begin_info);
+    NK_ASSERT(result == VK_SUCCESS);
+    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,
+                         VK_SUBPASS_CONTENTS_INLINE);
+
+    memset(&viewport, 0, sizeof(VkViewport));
+    viewport.width = (float)sdl.width;
+    viewport.height = (float)sdl.height;
+    viewport.maxDepth = 1.0f;
+    vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+
+    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                      dev->pipeline);
+    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                            dev->pipeline_layout, 0, 1,
+                            &dev->uniform_descriptor_set, 0, NULL);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        /* load draw vertices & elements directly into vertex + element buffer
+         */
+        {
+            /* fill convert 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_R8G8B8A8,
+                  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;
+
+            /* setup buffers to load vertices and elements */
+            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,
+                                 (size_t)dev->max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, dev->mapped_index,
+                                 (size_t)dev->max_element_buffer);
+            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+        }
+
+        /* iterate over and execute each draw command */
+
+        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,
+                               &doffset);
+        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,
+                             VK_INDEX_TYPE_UINT16);
+
+        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
+            if (!cmd->texture.ptr) {
+                continue;
+            }
+            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {
+                int found = 0;
+                uint32_t i;
+                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {
+                    if (dev->texture_descriptor_sets[i].image_view ==
+                        cmd->texture.ptr) {
+                        found = 1;
+                        break;
+                    }
+                }
+
+                if (!found) {
+                    update_texture_descriptor_set(
+                        dev, &dev->texture_descriptor_sets[i],
+                        (VkImageView)cmd->texture.ptr);
+                    dev->texture_descriptor_sets_len++;
+                }
+                vkCmdBindDescriptorSets(
+                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                    dev->pipeline_layout, 1, 1,
+                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);
+            }
+
+            if (!cmd->elem_count)
+                continue;
+
+            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f));
+            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f));
+            scissor.extent.width = (uint32_t)(cmd->clip_rect.w);
+            scissor.extent.height = (uint32_t)(cmd->clip_rect.h);
+            vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,
+                             0, 0);
+            index_offset += cmd->elem_count;
+        }
+        nk_clear(&sdl.ctx);
+    }
+
+    vkCmdEndRenderPass(command_buffer);
+    result = vkEndCommandBuffer(command_buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    if (wait_semaphore) {
+        wait_semaphore_count = 1;
+        wait_semaphores = &wait_semaphore;
+    } else {
+        wait_semaphore_count = 0;
+        wait_semaphores = NULL;
+    }
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+    submit_info.pWaitDstStageMask = &wait_stage;
+    submit_info.waitSemaphoreCount = wait_semaphore_count;
+    submit_info.pWaitSemaphores = wait_semaphores;
+    submit_info.signalSemaphoreCount = 1;
+    submit_info.pSignalSemaphores = &dev->render_completed;
+
+    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    return dev->render_completed;
+}
+
+NK_INTERN 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));
+    SDL_free((void *)text);
+    (void)usr;
+}
+
+NK_INTERN 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, VkDevice logical_device,
+            VkPhysicalDevice physical_device,
+            uint32_t graphics_queue_family_index, VkImageView *image_views,
+            uint32_t image_views_len, VkFormat color_format,
+            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,
+            VkDeviceSize max_element_buffer) {
+    (void)init_state;
+
+    memset(&sdl, 0, sizeof(struct nk_sdl));
+    sdl.win = win;
+
+    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);
+
+    SDL_GetWindowSize(win, &sdl.width, &sdl.height);
+    SDL_Vulkan_GetDrawableSize(win, &sdl.display_width, &sdl.display_height);
+    nk_sdl_device_create(logical_device, physical_device,
+                         graphics_queue_family_index, image_views,
+                         image_views_len, color_format, max_vertex_buffer,
+                         max_element_buffer, (uint32_t)sdl.display_width,
+                         (uint32_t)sdl.display_height);
+
+    return &sdl.ctx;
+}
+
+#endif

+ 12 - 0
demo/sdl_vulkan/shaders/demo.frag

@@ -0,0 +1,12 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(binding = 0) uniform sampler2D overlay;
+
+layout(location = 0) in vec2 inUV;
+
+layout(location = 0) out vec4 outColor;
+
+void main() {
+    outColor = texture(overlay, inUV);
+}

+ 10 - 0
demo/sdl_vulkan/shaders/demo.vert

@@ -0,0 +1,10 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout (location = 0) out vec2 outUV;
+
+void main()
+{
+    outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
+    gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);
+}

+ 11 - 0
demo/sdl_vulkan/src/Makefile

@@ -0,0 +1,11 @@
+create_shader_inlined_header: nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv
+	awk -v st='// NUKLEAR_SHADERS_START' -v et='// NUKLEAR_SHADERS_END' -v repl="$$(xxd -i nuklearshaders/nuklear.vert.spv && xxd -i nuklearshaders/nuklear.frag.spv)" '$$0 == st{del=1} $$0 == et{$$0 = repl; del=0} !del' nuklear_sdl_vulkan.in.h > nuklear_sdl_vulkan.h
+
+nuklearshaders/nuklear.vert.spv: nuklearshaders/nuklear.vert
+	glslc --target-env=vulkan nuklearshaders/nuklear.vert -o nuklearshaders/nuklear.vert.spv
+
+nuklearshaders/nuklear.frag.spv: nuklearshaders/nuklear.frag
+	glslc --target-env=vulkan nuklearshaders/nuklear.frag -o nuklearshaders/nuklear.frag.spv
+
+clean:
+	rm nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv nuklear_sdl_vulkan.h

+ 5 - 0
demo/sdl_vulkan/src/README.md

@@ -0,0 +1,5 @@
+Contrary to OpenGL Vulkan needs precompiled shaders in the SPIR-V format which makes it a bit more difficult to inline the shadercode.
+
+After executing `make` the result should be a self contained `nuklear_sdl_vulkan.h`. Copy the result file to the parent directory and the "release" should be done.
+
+You will need to have `xxd`, `glslc` and `awk` installed for this.

+ 1425 - 0
demo/sdl_vulkan/src/nuklear_sdl_vulkan.in.h

@@ -0,0 +1,1425 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warranty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_VULKAN_H_
+#define NK_SDL_VULKAN_H_
+
+// NUKLEAR_SHADERS_START
+// will be replaced with the real shader code
+// so we can have some ide support while editing the .in file
+#include "nuklear.h"
+
+unsigned char nuklearshaders_nuklear_vert_spv[] = {};
+unsigned int nuklearshaders_nuklear_vert_spv_len = 0;
+unsigned char nuklearshaders_nuklear_frag_spv[] = {};
+unsigned int nuklearshaders_nuklear_frag_spv_len = 0;
+// NUKLEAR_SHADERS_END
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <SDL2/SDL.h>
+
+enum nk_sdl_init_state { NK_SDL_DEFAULT = 0 };
+
+NK_API struct nk_context *
+nk_sdl_init(SDL_Window *win, VkDevice logical_device,
+            VkPhysicalDevice physical_device,
+            uint32_t graphics_queue_family_index, VkImageView *image_views,
+            uint32_t image_views_len, VkFormat color_format,
+            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,
+            VkDeviceSize max_element_buffer);
+NK_API void nk_sdl_shutdown(void);
+NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_sdl_font_stash_end(VkQueue graphics_queue);
+NK_API int nk_sdl_handle_event(SDL_Event *evt);
+NK_API VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,
+                                 VkSemaphore wait_semaphore,
+                                 enum nk_anti_aliasing AA);
+NK_API void nk_sdl_resize(uint32_t framebuffer_width,
+                          uint32_t framebuffer_height);
+NK_API void nk_sdl_device_destroy(void);
+NK_API void
+nk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,
+                     uint32_t graphics_queue_family_index,
+                     VkImageView *image_views, uint32_t image_views_len,
+                     VkFormat color_format, VkDeviceSize max_vertex_buffer,
+                     VkDeviceSize max_element_buffer,
+                     uint32_t framebuffer_width, uint32_t framebuffer_height);
+NK_API void nk_sdl_handle_grab(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_VULKAN_IMPLEMENTATION
+#undef NK_SDL_VULKAN_IMPLEMENTATION
+#include <stdlib.h>
+
+#ifndef NK_SDL_TEXT_MAX
+#define NK_SDL_TEXT_MAX 256
+#endif
+#ifndef NK_SDL_MAX_TEXTURES
+#define NK_SDL_MAX_TEXTURES 256
+#endif
+#ifndef NK_SDL_MAX_KEYS
+#define NK_SDL_MAX_KEYS 32
+#endif
+
+#define VK_COLOR_COMPONENT_MASK_RGBA                                           \
+    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \
+        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
+
+struct nk_sdl_vertex {
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+
+struct nk_vulkan_texture_descriptor_set {
+    VkImageView image_view;
+    VkDescriptorSet descriptor_set;
+};
+
+struct nk_sdl_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture tex_null;
+    int max_vertex_buffer;
+    int max_element_buffer;
+    VkDevice logical_device;
+    VkPhysicalDevice physical_device;
+    VkImageView *image_views;
+    uint32_t image_views_len;
+    VkFormat color_format;
+    VkFramebuffer *framebuffers;
+    uint32_t framebuffers_len;
+    VkCommandBuffer *command_buffers;
+    uint32_t command_buffers_len;
+    VkSampler sampler;
+    VkCommandPool command_pool;
+    VkSemaphore render_completed;
+    VkBuffer vertex_buffer;
+    VkDeviceMemory vertex_memory;
+    void *mapped_vertex;
+    VkBuffer index_buffer;
+    VkDeviceMemory index_memory;
+    void *mapped_index;
+    VkBuffer uniform_buffer;
+    VkDeviceMemory uniform_memory;
+    void *mapped_uniform;
+    VkRenderPass render_pass;
+    VkDescriptorPool descriptor_pool;
+    VkDescriptorSetLayout uniform_descriptor_set_layout;
+    VkDescriptorSet uniform_descriptor_set;
+    VkDescriptorSetLayout texture_descriptor_set_layout;
+    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;
+    uint32_t texture_descriptor_sets_len;
+    VkPipelineLayout pipeline_layout;
+    VkPipeline pipeline;
+    VkImage font_image;
+    VkImageView font_image_view;
+    VkDeviceMemory font_memory;
+};
+
+static struct nk_sdl {
+    SDL_Window *win;
+    int width, height;
+    int display_width, display_height;
+    struct nk_sdl_device vulkan;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    unsigned int text[NK_SDL_TEXT_MAX];
+    int text_len;
+    struct nk_vec2 scroll;
+    uint64_t delta_time_milliseconds_last;
+} sdl;
+
+struct Mat4f {
+    float m[16];
+};
+
+NK_INTERN uint32_t nk_sdl_find_memory_index(VkPhysicalDevice physical_device,
+                                            uint32_t type_filter,
+                                            VkMemoryPropertyFlags properties) {
+    VkPhysicalDeviceMemoryProperties mem_properties;
+    uint32_t i;
+
+    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);
+    for (i = 0; i < mem_properties.memoryTypeCount; i++) {
+        if ((type_filter & (1 << i)) &&
+            (mem_properties.memoryTypes[i].propertyFlags & properties) ==
+                properties) {
+            return i;
+        }
+    }
+
+    assert(0);
+    return 0;
+}
+
+NK_INTERN void nk_sdl_create_sampler(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkSamplerCreateInfo sampler_info;
+    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));
+
+    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+    sampler_info.pNext = NULL;
+    sampler_info.maxAnisotropy = 1.0;
+    sampler_info.magFilter = VK_FILTER_LINEAR;
+    sampler_info.minFilter = VK_FILTER_LINEAR;
+    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+    sampler_info.mipLodBias = 0.0f;
+    sampler_info.compareEnable = VK_FALSE;
+    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
+    sampler_info.minLod = 0.0f;
+    sampler_info.maxLod = 0.0f;
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+
+    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,
+                             &dev->sampler);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_command_pool(struct nk_sdl_device *dev,
+                           uint32_t graphics_queue_family_index) {
+    VkResult result;
+    VkCommandPoolCreateInfo pool_info;
+    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));
+
+    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_info.queueFamilyIndex = graphics_queue_family_index;
+    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,
+                                 &dev->command_pool);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_command_buffers(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkCommandBufferAllocateInfo allocate_info;
+    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));
+
+    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *
+                                                     sizeof(VkCommandBuffer));
+    dev->command_buffers_len = dev->image_views_len;
+
+    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    allocate_info.commandPool = dev->command_pool;
+    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    allocate_info.commandBufferCount = dev->command_buffers_len;
+
+    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,
+                                      dev->command_buffers);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_semaphore(struct nk_sdl_device *dev) {
+    VkResult result;
+    VkSemaphoreCreateInfo semaphore_info;
+    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));
+
+    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,
+                                &dev->render_completed));
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_buffer_and_memory(struct nk_sdl_device *dev,
+                                               VkBuffer *buffer,
+                                               VkBufferUsageFlags usage,
+                                               VkDeviceMemory *memory,
+                                               VkDeviceSize size) {
+    VkMemoryRequirements mem_reqs;
+    VkResult result;
+    VkBufferCreateInfo buffer_info;
+    VkMemoryAllocateInfo alloc_info;
+
+    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.size = size;
+    buffer_info.usage = usage;
+    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_render_pass(struct nk_sdl_device *dev) {
+    VkAttachmentDescription attachment;
+    VkAttachmentReference color_reference;
+    VkSubpassDependency subpass_dependency;
+    VkSubpassDescription subpass_description;
+    VkRenderPassCreateInfo render_pass_info;
+    VkResult result;
+
+    memset(&attachment, 0, sizeof(VkAttachmentDescription));
+    attachment.format = dev->color_format;
+    attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    memset(&color_reference, 0, sizeof(VkAttachmentReference));
+    color_reference.attachment = 0;
+    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));
+    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
+    subpass_dependency.srcAccessMask = 0;
+    subpass_dependency.srcStageMask =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    subpass_dependency.dstSubpass = 0;
+    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    subpass_dependency.dstStageMask =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+
+    memset(&subpass_description, 0, sizeof(VkSubpassDescription));
+    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    subpass_description.colorAttachmentCount = 1;
+    subpass_description.pColorAttachments = &color_reference;
+
+    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));
+    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    render_pass_info.attachmentCount = 1;
+    render_pass_info.pAttachments = &attachment;
+    render_pass_info.subpassCount = 1;
+    render_pass_info.pSubpasses = &subpass_description;
+    render_pass_info.dependencyCount = 1;
+    render_pass_info.pDependencies = &subpass_dependency;
+
+    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,
+                                &dev->render_pass);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_create_framebuffers(struct nk_sdl_device *dev,
+                                          uint32_t framebuffer_width,
+                                          uint32_t framebuffer_height) {
+
+    VkFramebufferCreateInfo framebuffer_create_info;
+    uint32_t i;
+    VkResult result;
+
+    dev->framebuffers =
+        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));
+
+    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));
+    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    framebuffer_create_info.renderPass = dev->render_pass;
+    framebuffer_create_info.attachmentCount = 1;
+    framebuffer_create_info.width = framebuffer_width;
+    framebuffer_create_info.height = framebuffer_height;
+    framebuffer_create_info.layers = 1;
+    for (i = 0; i < dev->image_views_len; i++) {
+        framebuffer_create_info.pAttachments = &dev->image_views[i];
+        result =
+            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,
+                                NULL, &dev->framebuffers[i]);
+        NK_ASSERT(result == VK_SUCCESS);
+    }
+    dev->framebuffers_len = dev->image_views_len;
+}
+
+NK_INTERN void nk_sdl_create_descriptor_pool(struct nk_sdl_device *dev) {
+    VkDescriptorPoolSize pool_sizes[2];
+    VkDescriptorPoolCreateInfo pool_info;
+    VkResult result;
+
+    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);
+    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    pool_sizes[0].descriptorCount = 1;
+    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    pool_sizes[1].descriptorCount = NK_SDL_MAX_TEXTURES;
+
+    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));
+    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    pool_info.poolSizeCount = 2;
+    pool_info.pPoolSizes = pool_sizes;
+    pool_info.maxSets = 1 + NK_SDL_MAX_TEXTURES;
+
+    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,
+                                    &dev->descriptor_pool);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_uniform_descriptor_set_layout(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayoutBinding binding;
+    VkDescriptorSetLayoutCreateInfo descriptor_set_info;
+    VkResult result;
+
+    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));
+    binding.binding = 0;
+    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    binding.descriptorCount = 1;
+    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+
+    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+    descriptor_set_info.sType =
+        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_set_info.bindingCount = 1;
+    descriptor_set_info.pBindings = &binding;
+
+    result =
+        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,
+                                    NULL, &dev->uniform_descriptor_set_layout);
+
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_and_update_uniform_descriptor_set(struct nk_sdl_device *dev) {
+    VkDescriptorSetAllocateInfo allocate_info;
+    VkDescriptorBufferInfo buffer_info;
+    VkWriteDescriptorSet descriptor_write;
+    VkResult result;
+
+    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));
+    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    allocate_info.descriptorPool = dev->descriptor_pool;
+    allocate_info.descriptorSetCount = 1;
+    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;
+
+    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,
+                                      &dev->uniform_descriptor_set);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));
+    buffer_info.buffer = dev->uniform_buffer;
+    buffer_info.offset = 0;
+    buffer_info.range = sizeof(struct Mat4f);
+
+    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = dev->uniform_descriptor_set;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.dstArrayElement = 0;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.pBufferInfo = &buffer_info;
+
+    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+NK_INTERN void
+nk_sdl_create_texture_descriptor_set_layout(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayoutBinding binding;
+    VkDescriptorSetLayoutCreateInfo descriptor_set_info;
+    VkResult result;
+
+    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));
+    binding.binding = 0;
+    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    binding.descriptorCount = 1;
+    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+
+    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));
+    descriptor_set_info.sType =
+        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_set_info.bindingCount = 1;
+    descriptor_set_info.pBindings = &binding;
+
+    result =
+        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,
+                                    NULL, &dev->texture_descriptor_set_layout);
+
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void
+nk_sdl_create_texture_descriptor_sets(struct nk_sdl_device *dev) {
+    VkDescriptorSetLayout *descriptor_set_layouts;
+    VkDescriptorSet *descriptor_sets;
+    VkDescriptorSetAllocateInfo allocate_info;
+    VkResult result;
+    int i;
+
+    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(
+        NK_SDL_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));
+    descriptor_sets = (VkDescriptorSet *)malloc(NK_SDL_MAX_TEXTURES *
+                                                sizeof(VkDescriptorSet));
+
+    dev->texture_descriptor_sets =
+        (struct nk_vulkan_texture_descriptor_set *)malloc(
+            NK_SDL_MAX_TEXTURES *
+            sizeof(struct nk_vulkan_texture_descriptor_set));
+    dev->texture_descriptor_sets_len = 0;
+
+    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {
+        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;
+        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;
+    }
+
+    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));
+    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    allocate_info.descriptorPool = dev->descriptor_pool;
+    allocate_info.descriptorSetCount = NK_SDL_MAX_TEXTURES;
+    allocate_info.pSetLayouts = descriptor_set_layouts;
+
+    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,
+                                      descriptor_sets);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {
+        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];
+    }
+    free(descriptor_set_layouts);
+    free(descriptor_sets);
+}
+
+NK_INTERN void nk_sdl_create_pipeline_layout(struct nk_sdl_device *dev) {
+    VkPipelineLayoutCreateInfo pipeline_layout_info;
+    VkDescriptorSetLayout descriptor_set_layouts[2];
+    VkResult result;
+
+    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;
+    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;
+
+    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));
+    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipeline_layout_info.setLayoutCount = 2;
+    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;
+
+    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,
+                                     NULL, &dev->pipeline_layout));
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN VkPipelineShaderStageCreateInfo
+nk_sdl_create_shader(struct nk_sdl_device *dev, unsigned char *spv_shader,
+                     uint32_t size, VkShaderStageFlagBits stage_bit) {
+    VkShaderModuleCreateInfo create_info;
+    VkPipelineShaderStageCreateInfo shader_info;
+    VkShaderModule module = NULL;
+    VkResult result;
+
+    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));
+    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    create_info.codeSize = size;
+    create_info.pCode = (const uint32_t *)spv_shader;
+    result =
+        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));
+    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    shader_info.stage = stage_bit;
+    shader_info.module = module;
+    shader_info.pName = "main";
+    return shader_info;
+}
+
+NK_INTERN void nk_sdl_create_pipeline(struct nk_sdl_device *dev) {
+    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;
+    VkPipelineRasterizationStateCreateInfo rasterization_state;
+    VkPipelineColorBlendAttachmentState attachment_state = {
+        VK_TRUE,
+        VK_BLEND_FACTOR_SRC_ALPHA,
+        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        VK_BLEND_OP_ADD,
+        VK_BLEND_FACTOR_SRC_ALPHA,
+        VK_BLEND_FACTOR_ONE,
+        VK_BLEND_OP_ADD,
+        VK_COLOR_COMPONENT_MASK_RGBA,
+    };
+    VkPipelineColorBlendStateCreateInfo color_blend_state;
+    VkPipelineViewportStateCreateInfo viewport_state;
+    VkPipelineMultisampleStateCreateInfo multisample_state;
+    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,
+                                        VK_DYNAMIC_STATE_SCISSOR};
+    VkPipelineDynamicStateCreateInfo dynamic_state;
+    VkPipelineShaderStageCreateInfo shader_stages[2];
+    VkVertexInputBindingDescription vertex_input_info;
+    VkVertexInputAttributeDescription vertex_attribute_description[3];
+    VkPipelineVertexInputStateCreateInfo vertex_input;
+    VkGraphicsPipelineCreateInfo pipeline_info;
+    VkResult result;
+
+    memset(&input_assembly_state, 0,
+           sizeof(VkPipelineInputAssemblyStateCreateInfo));
+    input_assembly_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+    input_assembly_state.primitiveRestartEnable = VK_FALSE;
+
+    memset(&rasterization_state, 0,
+           sizeof(VkPipelineRasterizationStateCreateInfo));
+    rasterization_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
+    rasterization_state.cullMode = VK_CULL_MODE_NONE;
+    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+    rasterization_state.lineWidth = 1.0f;
+
+    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));
+    color_blend_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+    color_blend_state.attachmentCount = 1;
+    color_blend_state.pAttachments = &attachment_state;
+
+    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));
+    viewport_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+    viewport_state.viewportCount = 1;
+    viewport_state.scissorCount = 1;
+
+    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));
+    multisample_state.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));
+    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+    dynamic_state.pDynamicStates = dynamic_states;
+    dynamic_state.dynamicStateCount = 2;
+
+    shader_stages[0] = nk_sdl_create_shader(
+        dev, nuklearshaders_nuklear_vert_spv,
+        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);
+    shader_stages[1] = nk_sdl_create_shader(
+        dev, nuklearshaders_nuklear_frag_spv,
+        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);
+
+    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));
+    vertex_input_info.binding = 0;
+    vertex_input_info.stride = sizeof(struct nk_sdl_vertex);
+    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+    memset(&vertex_attribute_description, 0,
+           sizeof(VkVertexInputAttributeDescription) * 3);
+    vertex_attribute_description[0].location = 0;
+    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;
+    vertex_attribute_description[0].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, position);
+    vertex_attribute_description[1].location = 1;
+    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;
+    vertex_attribute_description[1].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, uv);
+    vertex_attribute_description[2].location = 2;
+    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;
+    vertex_attribute_description[2].offset =
+        NK_OFFSETOF(struct nk_sdl_vertex, col);
+
+    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));
+    vertex_input.sType =
+        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+    vertex_input.vertexBindingDescriptionCount = 1;
+    vertex_input.pVertexBindingDescriptions = &vertex_input_info;
+    vertex_input.vertexAttributeDescriptionCount = 3;
+    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;
+
+    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));
+    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+    pipeline_info.flags = 0;
+    pipeline_info.stageCount = 2;
+    pipeline_info.pStages = shader_stages;
+    pipeline_info.pVertexInputState = &vertex_input;
+    pipeline_info.pInputAssemblyState = &input_assembly_state;
+    pipeline_info.pViewportState = &viewport_state;
+    pipeline_info.pRasterizationState = &rasterization_state;
+    pipeline_info.pMultisampleState = &multisample_state;
+    pipeline_info.pColorBlendState = &color_blend_state;
+    pipeline_info.pDynamicState = &dynamic_state;
+    pipeline_info.layout = dev->pipeline_layout;
+    pipeline_info.renderPass = dev->render_pass;
+    pipeline_info.basePipelineIndex = -1;
+    pipeline_info.basePipelineHandle = NULL;
+
+    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,
+                                       &pipeline_info, NULL, &dev->pipeline);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);
+    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);
+}
+
+NK_INTERN void nk_sdl_create_render_resources(struct nk_sdl_device *dev,
+                                              uint32_t framebuffer_width,
+                                              uint32_t framebuffer_height) {
+    nk_sdl_create_render_pass(dev);
+    nk_sdl_create_framebuffers(dev, framebuffer_width, framebuffer_height);
+    nk_sdl_create_descriptor_pool(dev);
+    nk_sdl_create_uniform_descriptor_set_layout(dev);
+    nk_sdl_create_and_update_uniform_descriptor_set(dev);
+    nk_sdl_create_texture_descriptor_set_layout(dev);
+    nk_sdl_create_texture_descriptor_sets(dev);
+    nk_sdl_create_pipeline_layout(dev);
+    nk_sdl_create_pipeline(dev);
+}
+
+NK_API void
+nk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,
+                     uint32_t graphics_queue_family_index,
+                     VkImageView *image_views, uint32_t image_views_len,
+                     VkFormat color_format, VkDeviceSize max_vertex_buffer,
+                     VkDeviceSize max_element_buffer,
+                     uint32_t framebuffer_width, uint32_t framebuffer_height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+    dev->max_vertex_buffer = max_vertex_buffer;
+    dev->max_element_buffer = max_element_buffer;
+    nk_buffer_init_default(&dev->cmds);
+    dev->logical_device = logical_device;
+    dev->physical_device = physical_device;
+    dev->image_views = image_views;
+    dev->image_views_len = image_views_len;
+    dev->color_format = color_format;
+    dev->framebuffers = NULL;
+    dev->framebuffers_len = 0;
+
+    nk_sdl_create_sampler(dev);
+    nk_sdl_create_command_pool(dev, graphics_queue_family_index);
+    nk_sdl_create_command_buffers(dev);
+    nk_sdl_create_semaphore(dev);
+
+    nk_sdl_create_buffer_and_memory(dev, &dev->vertex_buffer,
+                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+                                    &dev->vertex_memory, max_vertex_buffer);
+    nk_sdl_create_buffer_and_memory(dev, &dev->index_buffer,
+                                    VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
+                                    &dev->index_memory, max_element_buffer);
+    nk_sdl_create_buffer_and_memory(dev, &dev->uniform_buffer,
+                                    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+                                    &dev->uniform_memory, sizeof(struct Mat4f));
+
+    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,
+                0, &dev->mapped_vertex);
+    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,
+                0, &dev->mapped_index);
+    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,
+                sizeof(struct Mat4f), 0, &dev->mapped_uniform);
+
+    nk_sdl_create_render_resources(dev, framebuffer_width, framebuffer_height);
+}
+
+NK_INTERN void nk_sdl_device_upload_atlas(VkQueue graphics_queue,
+                                          const void *image, int width,
+                                          int height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    VkImageCreateInfo image_info;
+    VkResult result;
+    VkMemoryRequirements mem_reqs;
+    VkMemoryAllocateInfo alloc_info;
+    VkBufferCreateInfo buffer_info;
+    uint8_t *data = 0;
+    VkCommandBufferBeginInfo begin_info;
+    VkCommandBuffer command_buffer;
+    VkImageMemoryBarrier image_memory_barrier;
+    VkBufferImageCopy buffer_copy_region;
+    VkImageMemoryBarrier image_shader_memory_barrier;
+    VkFence fence;
+    VkFenceCreateInfo fence_create;
+    VkSubmitInfo submit_info;
+    VkImageViewCreateInfo image_view_info;
+    struct {
+        VkDeviceMemory memory;
+        VkBuffer buffer;
+    } staging_buffer;
+
+    memset(&image_info, 0, sizeof(VkImageCreateInfo));
+    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    image_info.imageType = VK_IMAGE_TYPE_2D;
+    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
+    image_info.extent.width = (uint32_t)width;
+    image_info.extent.height = (uint32_t)height;
+    image_info.extent.depth = 1;
+    image_info.mipLevels = 1;
+    image_info.arrayLayers = 1;
+    image_info.samples = VK_SAMPLE_COUNT_1_BIT;
+    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    image_info.usage =
+        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+    result =
+        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,
+                                 &mem_reqs);
+
+    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));
+    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,
+                              &dev->font_memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindImageMemory(dev->logical_device, dev->font_image,
+                               dev->font_memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));
+    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buffer_info.size = alloc_info.allocationSize;
+    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,
+                            &staging_buffer.buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,
+                                  &mem_reqs);
+
+    alloc_info.allocationSize = mem_reqs.size;
+    alloc_info.memoryTypeIndex =
+        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,
+                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,
+                              &staging_buffer.memory);
+    NK_ASSERT(result == VK_SUCCESS);
+    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,
+                                staging_buffer.memory, 0);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,
+                         alloc_info.allocationSize, 0, (void **)&data);
+    NK_ASSERT(result == VK_SUCCESS);
+    memcpy(data, image, width * height * 4);
+    vkUnmapMemory(dev->logical_device, staging_buffer.memory);
+
+    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    NK_ASSERT(dev->command_buffers_len > 0);
+    /*
+    use the same command buffer as for render as we are regenerating the
+    buffer during render anyway
+    */
+    command_buffer = dev->command_buffers[0];
+    result = vkBeginCommandBuffer(command_buffer, &begin_info);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_memory_barrier.image = dev->font_image;
+    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_memory_barrier.subresourceRange.levelCount = 1;
+    image_memory_barrier.subresourceRange.layerCount = 1;
+    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,
+                         &image_memory_barrier);
+
+    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));
+    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    buffer_copy_region.imageSubresource.layerCount = 1;
+    buffer_copy_region.imageExtent.width = (uint32_t)width;
+    buffer_copy_region.imageExtent.height = (uint32_t)height;
+    buffer_copy_region.imageExtent.depth = 1;
+
+    vkCmdCopyBufferToImage(
+        command_buffer, staging_buffer.buffer, dev->font_image,
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);
+
+    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));
+    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    image_shader_memory_barrier.image = dev->font_image;
+    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+    image_shader_memory_barrier.oldLayout =
+        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+    image_shader_memory_barrier.newLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+    image_shader_memory_barrier.subresourceRange.aspectMask =
+        VK_IMAGE_ASPECT_COLOR_BIT;
+    image_shader_memory_barrier.subresourceRange.levelCount = 1;
+    image_shader_memory_barrier.subresourceRange.layerCount = 1;
+    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+
+    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,
+                         NULL, 1, &image_shader_memory_barrier);
+
+    result = vkEndCommandBuffer(command_buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));
+    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+
+    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+
+    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);
+    NK_ASSERT(result == VK_SUCCESS);
+    result =
+        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    vkDestroyFence(dev->logical_device, fence, NULL);
+
+    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);
+    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);
+
+    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));
+    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    image_view_info.image = dev->font_image;
+    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    image_view_info.format = image_info.format;
+    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    image_view_info.subresourceRange.layerCount = 1;
+    image_view_info.subresourceRange.levelCount = 1;
+
+    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,
+                               &dev->font_image_view);
+    NK_ASSERT(result == VK_SUCCESS);
+}
+
+NK_INTERN void nk_sdl_destroy_render_resources(struct nk_sdl_device *dev) {
+    uint32_t i;
+
+    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);
+    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);
+    vkDestroyDescriptorSetLayout(dev->logical_device,
+                                 dev->texture_descriptor_set_layout, NULL);
+    vkDestroyDescriptorSetLayout(dev->logical_device,
+                                 dev->uniform_descriptor_set_layout, NULL);
+    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);
+    for (i = 0; i < dev->framebuffers_len; i++) {
+        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);
+    }
+    free(dev->framebuffers);
+    dev->framebuffers_len = 0;
+    free(dev->texture_descriptor_sets);
+    dev->texture_descriptor_sets_len = 0;
+    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);
+}
+
+NK_API void nk_sdl_resize(uint32_t framebuffer_width,
+                          uint32_t framebuffer_height) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    SDL_GetWindowSize(sdl.win, &sdl.width, &sdl.height);
+    sdl.display_width = framebuffer_width;
+    sdl.display_height = framebuffer_height;
+
+    nk_sdl_destroy_render_resources(dev);
+    nk_sdl_create_render_resources(dev, sdl.display_width, sdl.display_height);
+}
+
+NK_API void nk_sdl_device_destroy(void) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    vkDeviceWaitIdle(dev->logical_device);
+
+    nk_sdl_destroy_render_resources(dev);
+
+    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,
+                         dev->command_buffers_len, dev->command_buffers);
+    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);
+    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);
+
+    vkUnmapMemory(dev->logical_device, dev->vertex_memory);
+    vkUnmapMemory(dev->logical_device, dev->index_memory);
+    vkUnmapMemory(dev->logical_device, dev->uniform_memory);
+
+    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);
+    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);
+    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);
+
+    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);
+    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);
+    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);
+
+    vkDestroySampler(dev->logical_device, dev->sampler, NULL);
+
+    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);
+    vkDestroyImage(dev->logical_device, dev->font_image, NULL);
+    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);
+
+    free(dev->command_buffers);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_API
+void nk_sdl_shutdown(void) {
+    nk_font_atlas_clear(&sdl.atlas);
+    nk_free(&sdl.ctx);
+    nk_sdl_device_destroy();
+    memset(&sdl, 0, sizeof(sdl));
+}
+
+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(VkQueue graphics_queue) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+
+    const void *image;
+    int w, h;
+    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sdl_device_upload_atlas(graphics_queue, image, w, h);
+    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(dev->font_image_view),
+                      &dev->tex_null);
+    if (sdl.atlas.default_font) {
+        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+    }
+}
+
+NK_API void nk_sdl_handle_grab(void) {
+    struct nk_context *ctx = &sdl.ctx;
+    if (ctx->input.mouse.grab) {
+        SDL_SetRelativeMouseMode(SDL_TRUE);
+    } else if (ctx->input.mouse.ungrab) {
+        /* better support for older SDL by setting mode first; causes an extra
+         * mouse motion event */
+        SDL_SetRelativeMouseMode(SDL_FALSE);
+        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x,
+                              (int)ctx->input.mouse.prev.y);
+    } else if (ctx->input.mouse.grabbed) {
+        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+    }
+}
+
+NK_API int nk_sdl_handle_event(SDL_Event *evt) {
+    struct nk_context *ctx = &sdl.ctx;
+
+    switch (evt->type) {
+    case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */
+    case SDL_KEYDOWN: {
+        int down = evt->type == SDL_KEYDOWN;
+        const Uint8 *state = SDL_GetKeyboardState(0);
+        switch (evt->key.keysym.sym) {
+        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_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same
+                               routine */
+    case SDL_MOUSEBUTTONDOWN: {
+        int down = evt->type == SDL_MOUSEBUTTONDOWN;
+        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_MOUSEMOTION: {
+        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_TEXTINPUT: {
+        nk_glyph glyph;
+        memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+        nk_input_glyph(ctx, glyph);
+        return 1;
+    }
+
+    case SDL_MOUSEWHEEL:
+        nk_input_scroll(ctx, nk_vec2((float)evt->wheel.x, (float)evt->wheel.y));
+        return 1;
+    }
+    return 0;
+}
+
+NK_INTERN void update_texture_descriptor_set(
+    struct nk_sdl_device *dev,
+    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,
+    VkImageView image_view) {
+    VkDescriptorImageInfo descriptor_image_info;
+    VkWriteDescriptorSet descriptor_write;
+
+    texture_descriptor_set->image_view = image_view;
+
+    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));
+    descriptor_image_info.sampler = dev->sampler;
+    descriptor_image_info.imageView = texture_descriptor_set->image_view;
+    descriptor_image_info.imageLayout =
+        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));
+    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;
+    descriptor_write.dstBinding = 0;
+    descriptor_write.dstArrayElement = 0;
+    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+    descriptor_write.descriptorCount = 1;
+    descriptor_write.pImageInfo = &descriptor_image_info;
+
+    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);
+}
+
+NK_API
+VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,
+                          VkSemaphore wait_semaphore,
+                          enum nk_anti_aliasing AA) {
+    struct nk_sdl_device *dev = &sdl.vulkan;
+    struct nk_buffer vbuf, ebuf;
+
+    struct Mat4f projection = {
+        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
+         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},
+    };
+
+    VkCommandBufferBeginInfo begin_info;
+    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};
+    VkRenderPassBeginInfo render_pass_begin_nfo;
+    VkCommandBuffer command_buffer;
+    VkResult result;
+    VkViewport viewport;
+
+    VkDeviceSize doffset = 0;
+    VkImageView current_texture = NULL;
+    uint32_t index_offset = 0;
+    VkRect2D scissor;
+    uint32_t wait_semaphore_count;
+    VkSemaphore *wait_semaphores;
+    VkPipelineStageFlags wait_stage =
+        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    VkSubmitInfo submit_info;
+    uint64_t time_now;
+
+    time_now = SDL_GetTicks64();
+    sdl.ctx.delta_time_seconds =
+        (float)(time_now - sdl.delta_time_milliseconds_last) / 1000.0f;
+    sdl.delta_time_milliseconds_last = time_now;
+
+    projection.m[0] /= sdl.display_width;
+    projection.m[5] /= sdl.display_height;
+
+    memcpy(dev->mapped_uniform, &projection, sizeof(projection));
+
+    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+
+    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));
+    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    render_pass_begin_nfo.renderPass = dev->render_pass;
+    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)sdl.display_width;
+    render_pass_begin_nfo.renderArea.extent.height =
+        (uint32_t)sdl.display_height;
+    render_pass_begin_nfo.clearValueCount = 1;
+    render_pass_begin_nfo.pClearValues = &clear_value;
+    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];
+
+    command_buffer = dev->command_buffers[buffer_index];
+
+    result = vkBeginCommandBuffer(command_buffer, &begin_info);
+    NK_ASSERT(result == VK_SUCCESS);
+    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,
+                         VK_SUBPASS_CONTENTS_INLINE);
+
+    memset(&viewport, 0, sizeof(VkViewport));
+    viewport.width = (float)sdl.width;
+    viewport.height = (float)sdl.height;
+    viewport.maxDepth = 1.0f;
+    vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+
+    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                      dev->pipeline);
+    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                            dev->pipeline_layout, 0, 1,
+                            &dev->uniform_descriptor_set, 0, NULL);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        /* load draw vertices & elements directly into vertex + element buffer
+         */
+        {
+            /* fill convert 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_R8G8B8A8,
+                  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;
+
+            /* setup buffers to load vertices and elements */
+            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,
+                                 (size_t)dev->max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, dev->mapped_index,
+                                 (size_t)dev->max_element_buffer);
+            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+        }
+
+        /* iterate over and execute each draw command */
+
+        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,
+                               &doffset);
+        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,
+                             VK_INDEX_TYPE_UINT16);
+
+        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
+            if (!cmd->texture.ptr) {
+                continue;
+            }
+            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {
+                int found = 0;
+                uint32_t i;
+                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {
+                    if (dev->texture_descriptor_sets[i].image_view ==
+                        cmd->texture.ptr) {
+                        found = 1;
+                        break;
+                    }
+                }
+
+                if (!found) {
+                    update_texture_descriptor_set(
+                        dev, &dev->texture_descriptor_sets[i],
+                        (VkImageView)cmd->texture.ptr);
+                    dev->texture_descriptor_sets_len++;
+                }
+                vkCmdBindDescriptorSets(
+                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+                    dev->pipeline_layout, 1, 1,
+                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);
+            }
+
+            if (!cmd->elem_count)
+                continue;
+
+            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f));
+            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f));
+            scissor.extent.width = (uint32_t)(cmd->clip_rect.w);
+            scissor.extent.height = (uint32_t)(cmd->clip_rect.h);
+            vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,
+                             0, 0);
+            index_offset += cmd->elem_count;
+        }
+        nk_clear(&sdl.ctx);
+    }
+
+    vkCmdEndRenderPass(command_buffer);
+    result = vkEndCommandBuffer(command_buffer);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    if (wait_semaphore) {
+        wait_semaphore_count = 1;
+        wait_semaphores = &wait_semaphore;
+    } else {
+        wait_semaphore_count = 0;
+        wait_semaphores = NULL;
+    }
+
+    memset(&submit_info, 0, sizeof(VkSubmitInfo));
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+    submit_info.pWaitDstStageMask = &wait_stage;
+    submit_info.waitSemaphoreCount = wait_semaphore_count;
+    submit_info.pWaitSemaphores = wait_semaphores;
+    submit_info.signalSemaphoreCount = 1;
+    submit_info.pSignalSemaphores = &dev->render_completed;
+
+    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);
+    NK_ASSERT(result == VK_SUCCESS);
+
+    return dev->render_completed;
+}
+
+NK_INTERN 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));
+    SDL_free((void *)text);
+    (void)usr;
+}
+
+NK_INTERN 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, VkDevice logical_device,
+            VkPhysicalDevice physical_device,
+            uint32_t graphics_queue_family_index, VkImageView *image_views,
+            uint32_t image_views_len, VkFormat color_format,
+            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,
+            VkDeviceSize max_element_buffer) {
+    (void)init_state;
+
+    memset(&sdl, 0, sizeof(struct nk_sdl));
+    sdl.win = win;
+
+    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);
+
+    SDL_GetWindowSize(win, &sdl.width, &sdl.height);
+    SDL_Vulkan_GetDrawableSize(win, &sdl.display_width, &sdl.display_height);
+    nk_sdl_device_create(logical_device, physical_device,
+                         graphics_queue_family_index, image_views,
+                         image_views_len, color_format, max_vertex_buffer,
+                         max_element_buffer, (uint32_t)sdl.display_width,
+                         (uint32_t)sdl.display_height);
+
+    return &sdl.ctx;
+}
+
+#endif

+ 13 - 0
demo/sdl_vulkan/src/nuklearshaders/nuklear.frag

@@ -0,0 +1,13 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(binding = 0, set = 1) uniform sampler2D currentTexture;
+
+layout(location = 0) in vec4 fragColor;
+layout(location = 1) in vec2 fragUv;
+layout(location = 0) out vec4 outColor;
+
+void main() {
+    vec4 texColor = texture(currentTexture, fragUv);
+    outColor = fragColor * texColor;
+}

+ 23 - 0
demo/sdl_vulkan/src/nuklearshaders/nuklear.vert

@@ -0,0 +1,23 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+out gl_PerVertex {
+    vec4 gl_Position;
+};
+
+layout(binding = 0) uniform UniformBufferObject {
+    mat4 projection;
+} ubo;
+
+layout(location = 0) in vec2 position;
+layout(location = 1) in vec2 uv;
+layout(location = 2) in uvec4 color;
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec2 fragUv;
+
+void main() {
+    gl_Position = ubo.projection * vec4(position, 0.0, 1.0);
+    gl_Position.y = -gl_Position.y;
+    fragColor = vec4(color[0]/255.0, color[1]/255.0, color[2]/255.0, color[3]/255.0);
+    fragUv = uv;
+}

+ 1 - 1
demo/sfml_opengl2/main.cpp

@@ -38,7 +38,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/sfml_opengl3/main.cpp

@@ -40,7 +40,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/x11/Makefile

@@ -1,5 +1,5 @@
 # Install
-BIN = zahnrad
+BIN = demo
 
 # Flags
 CFLAGS += -std=c89 -Wall -Wextra -pedantic -Wno-unused-function

+ 1 - 1
demo/x11/main.c

@@ -80,7 +80,7 @@ sleep_for(long t)
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 3 - 3
demo/x11_opengl2/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Compiler
-CC = clang
+CC ?= clang
 DCC = gcc
 
 # Flags
@@ -13,11 +13,11 @@ OBJ = $(SRC:.c=.o)
 
 # Modes
 .PHONY: gcc
-gcc: CC = gcc
+gcc: CC ?= gcc
 gcc: $(BIN)
 
 .PHONY: clang
-clang: CC = clang
+clang: CC ?= clang
 clang: $(BIN)
 
 $(BIN):

+ 1 - 1
demo/x11_opengl2/main.c

@@ -41,7 +41,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 3 - 3
demo/x11_opengl3/Makefile

@@ -2,7 +2,7 @@
 BIN = demo
 
 # Compiler
-CC = clang
+CC ?= clang
 DCC = gcc
 
 # Flags
@@ -13,11 +13,11 @@ OBJ = $(SRC:.c=.o)
 
 # Modes
 .PHONY: gcc
-gcc: CC = gcc
+gcc: CC ?= gcc
 gcc: $(BIN)
 
 .PHONY: clang
-clang: CC = clang
+clang: CC ?= clang
 clang: $(BIN)
 
 $(BIN):

+ 1 - 1
demo/x11_opengl3/main.c

@@ -39,7 +39,7 @@
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/x11_xft/Makefile

@@ -1,5 +1,5 @@
 # Install
-BIN = zahnrad
+BIN = demo
 
 # Flags
 CFLAGS += -std=c89 -Wall -Wextra -pedantic -Wno-unused-function

+ 1 - 1
demo/x11_xft/main.c

@@ -80,7 +80,7 @@ sleep_for(long t)
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
 /*#define INCLUDE_CANVAS */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 
 #ifdef INCLUDE_ALL

+ 1 - 1
demo/xcb_cairo/main.c

@@ -41,7 +41,7 @@ static void die(const char *fmt, ...)
 /*#define INCLUDE_ALL */
 /*#define INCLUDE_STYLE */
 /*#define INCLUDE_CALCULATOR */
-/*#define INCLUDE_OVERVIEW */
+#define INCLUDE_OVERVIEW
 /*#define INCLUDE_NODE_EDITOR */
 /*#define INCLUDE_CANVAS */
 

+ 2739 - 0
doc/Doxyfile

@@ -0,0 +1,2739 @@
+# Doxyfile 1.9.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Nuklear"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI."
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ./doc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# numer of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL   = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT       = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =    "./src" \
+                            "./src/HEADER.md" \
+                            "./Readme.md"
+
+
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.l \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = "./src/Readme.md" \
+                            "./src/paq.sh" \
+                            "./src/paq.bat" 
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = Readme.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = ./doc/doxygen-awesome-css/doxygen-awesome.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR           = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        =
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
+# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
+# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES

+ 0 - 26
doc/Makefile

@@ -1,26 +0,0 @@
-# Install
-BIN = doc
-
-# Flags
-CFLAGS += -std=c99 -pedantic
-
-SRC = stddoc.c
-OBJ = $(SRC:.c=.o)
-
-ifeq ($(OS),Windows_NT)
-BIN := $(BIN).exe
-LIBS =
-else
-	UNAME_S := $(shell uname -s)
-	ifeq ($(UNAME_S),Darwin)
-		LIBS =
-	else
-		LIBS =
-	endif
-endif
-
-$(BIN): clean
-	$(CC) $(SRC) $(CFLAGS) -o $(BIN)
-
-clean:
-	rm -f $(BIN) $(OBJS)

+ 0 - 2
doc/build.sh

@@ -1,2 +0,0 @@
-#!/bin/sh
-cat ../nuklear.h|./doc > index.html

+ 0 - 2974
doc/index.html

@@ -1,2974 +0,0 @@
-<meta charset='utf-8' emacsmode='-*- markdown -*-'>
-<link rel='stylesheet' href='https://casual-effects.com/markdeep/latest/apidoc.css?'>
-# Nuklear
-![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
-## Contents
-1. About section
-2. Highlights section
-3. Features section
-4. Usage section
-    1. Flags section
-    2. Constants section
-    3. Dependencies section
-5. Example section
-6. API section
-    1. Context section
-    2. Input section
-    3. Drawing section
-    4. Window section
-    5. Layouting section
-    6. Groups section
-    7. Tree section
-    8. Properties section
-7. License section
-8. Changelog section
-9. Gallery section
-10. Credits section
-## About
-This is a minimal state immediate mode graphical user interface toolkit
-written in ANSI C and licensed under public domain. It was designed as a simple
-embeddable user interface for application and does not have any dependencies,
-a default renderbackend or OS window and input handling but instead provides a very modular
-library approach by using simple input state for input and draw
-commands describing primitive shapes as output. So instead of providing a
-layered library that tries to abstract over a number of platform and
-render backends it only focuses on the actual UI.
-## Highlights
-- Graphical user interface toolkit
-- Single header library
-- Written in C89 (a.k.a. ANSI C or ISO C90)
-- Small codebase (~18kLOC)
-- Focus on portability, efficiency and simplicity
-- No dependencies (not even the standard library if not wanted)
-- Fully skinnable and customizable
-- Low memory footprint with total memory control if needed or wanted
-- UTF-8 support
-- No global or hidden state
-- Customizable library modules (you can compile and use only what you need)
-- Optional font baker and vertex buffer output
-- [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)
-## Features
-- Absolutely no platform dependent code
-- Memory management control ranging from/to
-    - Ease of use by allocating everything from standard library
-    - Control every byte of memory inside the library
-- Font handling control ranging from/to
-    - Use your own font implementation for everything
-    - Use this libraries internal font baking and handling API
-- Drawing output control ranging from/to
-    - Simple shapes for more high level APIs which already have drawing capabilities
-    - Hardware accessible anti-aliased vertex buffer output
-- Customizable colors and properties ranging from/to
-    - Simple changes to color by filling a simple color table
-    - Complete control with ability to use skinning to decorate widgets
-- Bendable UI library with widget ranging from/to
-    - Basic widgets like buttons, checkboxes, slider, ...
-    - Advanced widget like abstract comboboxes, contextual menus,...
-- Compile time configuration to only compile what you need
-    - Subset which can be used if you do not want to link or use the standard library
-- Can be easily modified to only update on user input instead of frame updates
-## Usage
-This library is self contained in one single header file and can be used either
-in header only mode or in implementation mode. The header only mode is used
-by default when included and allows including this header in other headers
-and does not contain the actual implementation. <br /><br />
-The implementation mode requires to define  the preprocessor macro
-NK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C
-    #define NK_IMPLEMENTATION
-    #include "nuklear.h"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
-below in header and implementation mode if you want to use additional functionality
-or need more control over the library.
-!!! WARNING
-    Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.
-### Flags
-Flag                            | Description
---------------------------------|------------------------------------------
-NK_PRIVATE                      | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation
-NK_INCLUDE_FIXED_TYPES          | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
-NK_INCLUDE_DEFAULT_ALLOCATOR    | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
-NK_INCLUDE_STANDARD_IO          | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
-NK_INCLUDE_STANDARD_VARARGS     | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
-NK_INCLUDE_STANDARD_BOOL        | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
-NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
-NK_INCLUDE_FONT_BAKING          | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
-NK_INCLUDE_DEFAULT_FONT         | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
-NK_INCLUDE_COMMAND_USERDATA     | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.
-NK_BUTTON_TRIGGER_ON_RELEASE    | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.
-NK_ZERO_COMMAND_MEMORY          | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.
-NK_UINT_DRAW_INDEX              | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit
-NK_KEYSTATE_BASED_INPUT         | Define this if your backend uses key state for each frame rather than key press/release events
-!!! WARNING
-    The following flags will pull in the standard C library:
-    - NK_INCLUDE_DEFAULT_ALLOCATOR
-    - NK_INCLUDE_STANDARD_IO
-    - NK_INCLUDE_STANDARD_VARARGS
-!!! WARNING
-    The following flags if defined need to be defined for both header and implementation:
-    - NK_INCLUDE_FIXED_TYPES
-    - NK_INCLUDE_DEFAULT_ALLOCATOR
-    - NK_INCLUDE_STANDARD_VARARGS
-    - NK_INCLUDE_STANDARD_BOOL
-    - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
-    - NK_INCLUDE_FONT_BAKING
-    - NK_INCLUDE_DEFAULT_FONT
-    - NK_INCLUDE_STANDARD_VARARGS
-    - NK_INCLUDE_COMMAND_USERDATA
-    - NK_UINT_DRAW_INDEX
-### Constants
-Define                          | Description
---------------------------------|---------------------------------------
-NK_BUFFER_DEFAULT_INITIAL_SIZE  | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.
-NK_MAX_NUMBER_BUFFER            | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.
-NK_INPUT_MAX                    | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.
-!!! WARNING
-    The following constants if defined need to be defined for both header and implementation:
-    - NK_MAX_NUMBER_BUFFER
-    - NK_BUFFER_DEFAULT_INITIAL_SIZE
-    - NK_INPUT_MAX
-### Dependencies
-Function    | Description
-------------|---------------------------------------------------------------
-NK_ASSERT   | If you don't define this, nuklear will use <assert.h> with assert().
-NK_MEMSET   | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
-NK_MEMCPY   | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
-NK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
-NK_SIN      | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
-NK_COS      | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
-NK_STRTOD   | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
-NK_DTOA     | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
-NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
-!!! WARNING
-    The following dependencies will pull in the standard C library if not redefined:
-    - NK_ASSERT
-!!! WARNING
-    The following dependencies if defined need to be defined for both header and implementation:
-    - NK_ASSERT
-!!! WARNING
-    The following dependencies if defined need to be defined only for the implementation part:
-    - NK_MEMSET
-    - NK_MEMCPY
-    - NK_SQRT
-    - NK_SIN
-    - NK_COS
-    - NK_STRTOD
-    - NK_DTOA
-    - NK_VSNPRINTF
-## Example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-// init gui state
-enum {EASY, HARD};
-static int op = EASY;
-static float value = 0.6f;
-static int i =  20;
-struct nk_context ctx;
-nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
-if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
-    NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
-    // fixed widget pixel width
-    nk_layout_row_static(&ctx, 30, 80, 1);
-    if (nk_button_label(&ctx, "button")) {
-        // event handling
-    }
-    // fixed widget window ratio width
-    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;
-    // custom widget pixel width
-    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
-    {
-        nk_layout_row_push(&ctx, 50);
-        nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
-        nk_layout_row_push(&ctx, 110);
-        nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
-    }
-    nk_layout_row_end(&ctx);
-}
-nk_end(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
-## API
-### Context
-Contexts are the main entry point and the majestro of nuklear and contain all required state.
-They are used for window, memory, input, style, stack, commands and time management and need
-to be passed into all nuklear GUI specific functions.
-#### Usage
-To use a context it first has to be initialized which can be achieved by calling
-one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`.
-Each takes in a font handle and a specific way of handling memory. Memory control
-hereby ranges from standard library to just specifying a fixed sized block of memory
-which nuklear has to manage itself from.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    // [...]
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function            | Description
---------------------|-------------------------------------------------------
-__nk_init_default__ | Initializes context with standard library memory allocation (malloc,free)
-__nk_init_fixed__   | Initializes context from single fixed size memory block
-__nk_init__         | Initializes context with memory allocator callbacks for alloc and free
-__nk_init_custom__  | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations
-__nk_clear__        | Called at the end of the frame to reset and prepare the context for the next frame
-__nk_free__         | Shutdown and free all memory allocated inside the context
-__nk_set_user_data__| Utility function to pass user data to draw command
-#### nk_init_default
-Initializes a `nk_context` struct with a default standard library allocator.
-Should be used if you don't want to be bothered with memory management in nuklear.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_init_default(struct nk_context *ctx, const struct nk_user_font *font);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|---------------------------------------------------------------
-__ctx__     | Must point to an either stack or heap allocated `nk_context` struct
-__font__    | Must point to a previously initialized font handle for more info look at font documentation
-Returns either `false(0)` on failure or `true(1)` on success.
-#### nk_init_fixed
-Initializes a `nk_context` struct from single fixed size memory block
-Should be used if you want complete control over nuklear's memory management.
-Especially recommended for system with little memory or systems with virtual memory.
-For the later case you can just allocate for example 16MB of virtual memory
-and only the required amount of memory will actually be committed.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-!!! Warning
-    make sure the passed memory block is aligned correctly for `nk_draw_commands`.
-Parameter   | Description
-------------|--------------------------------------------------------------
-__ctx__     | Must point to an either stack or heap allocated `nk_context` struct
-__memory__  | Must point to a previously allocated memory block
-__size__    | Must contain the total size of __memory__
-__font__    | Must point to a previously initialized font handle for more info look at font documentation
-Returns either `false(0)` on failure or `true(1)` on success.
-#### nk_init
-Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate
-memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation
-interface to nuklear. Can be useful for cases like monitoring memory consumption.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_init(struct nk_context *ctx, struct nk_allocator *alloc, const struct nk_user_font *font);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|---------------------------------------------------------------
-__ctx__     | Must point to an either stack or heap allocated `nk_context` struct
-__alloc__   | Must point to a previously allocated memory allocator
-__font__    | Must point to a previously initialized font handle for more info look at font documentation
-Returns either `false(0)` on failure or `true(1)` on success.
-#### nk_init_custom
-Initializes a `nk_context` struct from two different either fixed or growing
-buffers. The first buffer is for allocating draw commands while the second buffer is
-used for allocating windows, panels and state tables.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|---------------------------------------------------------------
-__ctx__     | Must point to an either stack or heap allocated `nk_context` struct
-__cmds__    | Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into
-__pool__    | Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables
-__font__    | Must point to a previously initialized font handle for more info look at font documentation
-Returns either `false(0)` on failure or `true(1)` on success.
-#### nk_clear
-Resets the context state at the end of the frame. This includes mostly
-garbage collector tasks like removing windows or table not called and therefore
-used anymore.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_clear(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-#### nk_free
-Frees all memory allocated by nuklear. Not needed if context was
-initialized with `nk_init_fixed`.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_free(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-#### nk_set_user_data
-Sets the currently passed userdata passed down into each draw command.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_set_user_data(struct nk_context *ctx, nk_handle data);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|--------------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__data__    | Handle with either pointer or index to be passed into every draw commands
-### Input
-The input API is responsible for holding the current input state composed of
-mouse, key and text input states.
-It is worth noting that no direct OS or window handling is done in nuklear.
-Instead all input state has to be provided by platform specific code. This on one hand
-expects more work from the user and complicates usage but on the other hand
-provides simple abstraction over a big number of platforms, libraries and other
-already provided functionality.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_input_begin(&ctx);
-while (GetEvent(&evt)) {
-    if (evt.type == MOUSE_MOVE)
-        nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-    else if (evt.type == [...]) {
-        // [...]
-    }
-} nk_input_end(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Usage
-Input state needs to be provided to nuklear by first calling `nk_input_begin`
-which resets internal state like delta mouse position and button transitions.
-After `nk_input_begin` all current input state needs to be provided. This includes
-mouse motion, button and key pressed and released, text input and scrolling.
-Both event- or state-based input handling are supported by this API
-and should work without problems. Finally after all input state has been
-mirrored `nk_input_end` needs to be called to finish input process.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    Event evt;
-    nk_input_begin(&ctx);
-    while (GetEvent(&evt)) {
-        if (evt.type == MOUSE_MOVE)
-            nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-        else if (evt.type == [...]) {
-            // [...]
-        }
-    }
-    nk_input_end(&ctx);
-    // [...]
-    nk_clear(&ctx);
-} nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function            | Description
---------------------|-------------------------------------------------------
-__nk_input_begin__  | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls
-__nk_input_motion__ | Mirrors mouse cursor position
-__nk_input_key__    | Mirrors key state with either pressed or released
-__nk_input_button__ | Mirrors mouse button state with either pressed or released
-__nk_input_scroll__ | Mirrors mouse scroll values
-__nk_input_char__   | Adds a single ASCII text character into an internal text buffer
-__nk_input_glyph__  | Adds a single multi-byte UTF-8 character into an internal text buffer
-__nk_input_unicode__| Adds a single unicode rune into an internal text buffer
-__nk_input_end__    | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call
-#### nk_input_begin
-Begins the input mirroring process by resetting text, scroll
-mouse, previous mouse position and movement as well as key state transitions,
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_begin(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-#### nk_input_motion
-Mirrors current mouse position to nuklear
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_motion(struct nk_context *ctx, int x, int y);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__x__       | Must hold an integer describing the current mouse cursor x-position
-__y__       | Must hold an integer describing the current mouse cursor y-position
-#### nk_input_key
-Mirrors the state of a specific key to nuklear
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_key(struct nk_context*, enum nk_keys key, nk_bool down);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__key__     | Must be any value specified in enum `nk_keys` that needs to be mirrored
-__down__    | Must be 0 for key is up and 1 for key is down
-#### nk_input_button
-Mirrors the state of a specific mouse button to nuklear
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, nk_bool down);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__btn__     | Must be any value specified in enum `nk_buttons` that needs to be mirrored
-__x__       | Must contain an integer describing mouse cursor x-position on click up/down
-__y__       | Must contain an integer describing mouse cursor y-position on click up/down
-__down__    | Must be 0 for key is up and 1 for key is down
-#### nk_input_scroll
-Copies the last mouse scroll value to nuklear. Is generally
-a scroll value. So does not have to come from mouse and could also originate
-TODO finish this sentence
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__val__     | vector with both X- as well as Y-scroll value
-#### nk_input_char
-Copies a single ASCII character into an internal text buffer
-This is basically a helper function to quickly push ASCII characters into
-nuklear.
-!!! Note
-    Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_char(struct nk_context *ctx, char c);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__c__       | Must be a single ASCII character preferable one that can be printed
-#### nk_input_glyph
-Converts an encoded unicode rune into UTF-8 and copies the result into an
-internal text buffer.
-!!! Note
-    Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_glyph(struct nk_context *ctx, const nk_glyph g);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__g__       | UTF-32 unicode codepoint
-#### nk_input_unicode
-Converts a unicode rune into UTF-8 and copies the result
-into an internal text buffer.
-!!! Note
-    Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_unicode(struct nk_context*, nk_rune rune);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-__rune__    | UTF-32 unicode codepoint
-#### nk_input_end
-End the input mirroring process by resetting mouse grabbing
-state to ensure the mouse cursor is not grabbed indefinitely.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_input_end(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to a previously initialized `nk_context` struct
-### Drawing
-This library was designed to be render backend agnostic so it does
-not draw anything to screen directly. Instead all drawn shapes, widgets
-are made of, are buffered into memory and make up a command queue.
-Each frame therefore fills the command buffer with draw commands
-that then need to be executed by the user and his own render backend.
-After that the command buffer needs to be cleared and a new frame can be
-started. It is probably important to note that the command buffer is the main
-drawing API and the optional vertex buffer API only takes this format and
-converts it into a hardware accessible format.
-#### Usage
-To draw all draw commands accumulated over a frame you need your own render
-backend able to draw a number of 2D primitives. This includes at least
-filled and stroked rectangles, circles, text, lines, triangles and scissors.
-As soon as this criterion is met you can iterate over each draw command
-and execute each draw command in a interpreter like fashion:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_command *cmd = 0;
-nk_foreach(cmd, &ctx) {
-    switch (cmd->type) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case //...:
-        //[...]
-    }
-}
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In program flow context draw commands need to be executed after input has been
-gathered and the complete UI with windows and their contained widgets have
-been executed and before calling `nk_clear` which frees all previously
-allocated draw commands.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    Event evt;
-    nk_input_begin(&ctx);
-    while (GetEvent(&evt)) {
-        if (evt.type == MOUSE_MOVE)
-            nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-        else if (evt.type == [...]) {
-            [...]
-        }
-    }
-    nk_input_end(&ctx);
-    //
-    // [...]
-    //
-    const struct nk_command *cmd = 0;
-    nk_foreach(cmd, &ctx) {
-    switch (cmd->type) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case ...:
-        // [...]
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You probably noticed that you have to draw all of the UI each frame which is
-quite wasteful. While the actual UI updating loop is quite fast rendering
-without actually needing it is not. So there are multiple things you could do.
-First is only update on input. This of course is only an option if your
-application only depends on the UI and does not require any outside calculations.
-If you actually only update on input make sure to update the UI two times each
-frame and call `nk_clear` directly after the first pass and only draw in
-the second pass. In addition it is recommended to also add additional timers
-to make sure the UI is not drawn more than a fixed number of frames per second.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    // [...wait for input ]
-    // [...do two UI passes ...]
-    do_ui(...)
-    nk_clear(&ctx);
-    do_ui(...)
-    //
-    // draw
-    const struct nk_command *cmd = 0;
-    nk_foreach(cmd, &ctx) {
-    switch (cmd->type) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case ...:
-        //[...]
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The second probably more applicable trick is to only draw if anything changed.
-It is not really useful for applications with continuous draw loop but
-quite useful for desktop applications. To actually get nuklear to only
-draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and
-allocate a memory buffer that will store each unique drawing output.
-After each frame you compare the draw command memory inside the library
-with your allocated buffer by memcmp. If memcmp detects differences
-you have to copy the command buffer into the allocated buffer
-and then draw like usual (this example uses fixed memory but you could
-use dynamically allocated memory).
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-//[... other defines ...]
-#define NK_ZERO_COMMAND_MEMORY
-#include "nuklear.h"
-//
-// setup context
-struct nk_context ctx;
-void *last = calloc(1,64*1024);
-void *buf = calloc(1,64*1024);
-nk_init_fixed(&ctx, buf, 64*1024);
-//
-// loop
-while (1) {
-    // [...input...]
-    // [...ui...]
-    void *cmds = nk_buffer_memory(&ctx.memory);
-    if (memcmp(cmds, last, ctx.memory.allocated)) {
-        memcpy(last,cmds,ctx.memory.allocated);
-        const struct nk_command *cmd = 0;
-        nk_foreach(cmd, &ctx) {
-            switch (cmd->type) {
-            case NK_COMMAND_LINE:
-                your_draw_line_function(...)
-                break;
-            case NK_COMMAND_RECT
-                your_draw_rect_function(...)
-                break;
-            case ...:
-                // [...]
-            }
-        }
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Finally while using draw commands makes sense for higher abstracted platforms like
-X11 and Win32 or drawing libraries it is often desirable to use graphics
-hardware directly. Therefore it is possible to just define
-`NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output.
-To access the vertex output you first have to convert all draw commands into
-vertexes by calling `nk_convert` which takes in your preferred vertex format.
-After successfully converting all draw commands just iterate over and execute all
-vertex draw commands:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-// fill configuration
-struct your_vertex
-{
-    float pos[2]; // important to keep it to 2 floats
-    float uv[2];
-    unsigned char col[4];
-};
-struct nk_convert_config cfg = {};
-static const struct nk_draw_vertex_layout_element vertex_layout[] = {
-    {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)},
-    {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)},
-    {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)},
-    {NK_VERTEX_LAYOUT_END}
-};
-cfg.shape_AA = NK_ANTI_ALIASING_ON;
-cfg.line_AA = NK_ANTI_ALIASING_ON;
-cfg.vertex_layout = vertex_layout;
-cfg.vertex_size = sizeof(struct your_vertex);
-cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex);
-cfg.circle_segment_count = 22;
-cfg.curve_segment_count = 22;
-cfg.arc_segment_count = 22;
-cfg.global_alpha = 1.0f;
-cfg.tex_null = dev->tex_null;
-//
-// setup buffers and convert
-struct nk_buffer cmds, verts, idx;
-nk_buffer_init_default(&cmds);
-nk_buffer_init_default(&verts);
-nk_buffer_init_default(&idx);
-nk_convert(&ctx, &cmds, &verts, &idx, &cfg);
-//
-// draw
-nk_draw_foreach(cmd, &ctx, &cmds) {
-if (!cmd->elem_count) continue;
-    //[...]
-}
-nk_buffer_free(&cms);
-nk_buffer_free(&verts);
-nk_buffer_free(&idx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function            | Description
---------------------|-------------------------------------------------------
-__nk__begin__       | Returns the first draw command in the context draw command list to be drawn
-__nk__next__        | Increments the draw command iterator to the next command inside the context draw command list
-__nk_foreach__      | Iterates over each draw command inside the context draw command list
-__nk_convert__      | Converts from the abstract draw commands list into a hardware accessible vertex format
-__nk_draw_begin__   | Returns the first vertex command in the context vertex draw list to be executed
-__nk__draw_next__   | Increments the vertex command iterator to the next command inside the context vertex command list
-__nk__draw_end__    | Returns the end of the vertex draw list
-__nk_draw_foreach__ | Iterates over each vertex draw command inside the vertex draw list
-#### nk__begin
-Returns a draw command list iterator to iterate all draw
-commands accumulated over one frame.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_command* nk__begin(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | must point to an previously initialized `nk_context` struct at the end of a frame
-Returns draw command pointer pointing to the first command inside the draw command list
-#### nk__next
-Returns draw command pointer pointing to the next command inside the draw command list
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-__cmd__     | Must point to an previously a draw command either returned by `nk__begin` or `nk__next`
-Returns draw command pointer pointing to the next command inside the draw command list
-#### nk_foreach
-Iterates over each draw command inside the context draw command list
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_foreach(c, ctx)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-__cmd__     | Command pointer initialized to NULL
-Iterates over each draw command inside the context draw command list
-#### nk_convert
-Converts all internal draw commands into vertex draw commands and fills
-three buffers with vertexes, vertex draw commands and vertex indices. The vertex format
-as well as some other configuration values have to be configured by filling out a
-`nk_convert_config` struct.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,
-    struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-__cmds__    | Must point to a previously initialized buffer to hold converted vertex draw commands
-__vertices__| Must point to a previously initialized buffer to hold all produced vertices
-__elements__| Must point to a previously initialized buffer to hold all produced vertex indices
-__config__  | Must point to a filled out `nk_config` struct to configure the conversion process
-Returns one of enum nk_convert_result error codes
-Parameter                       | Description
---------------------------------|-----------------------------------------------------------
-NK_CONVERT_SUCCESS              | Signals a successful draw command to vertex buffer conversion
-NK_CONVERT_INVALID_PARAM        | An invalid argument was passed in the function call
-NK_CONVERT_COMMAND_BUFFER_FULL  | The provided buffer for storing draw commands is full or failed to allocate more memory
-NK_CONVERT_VERTEX_BUFFER_FULL   | The provided buffer for storing vertices is full or failed to allocate more memory
-NK_CONVERT_ELEMENT_BUFFER_FULL  | The provided buffer for storing indices is full or failed to allocate more memory
-#### nk__draw_begin
-Returns a draw vertex command buffer iterator to iterate over the vertex draw command buffer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-__buf__     | Must point to an previously by `nk_convert` filled out vertex draw command buffer
-Returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer
-#### nk__draw_end
-Returns the vertex draw command at the end of the vertex draw command buffer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-__buf__     | Must point to an previously by `nk_convert` filled out vertex draw command buffer
-Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer
-#### nk__draw_next
-Increments the vertex draw command buffer iterator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__cmd__     | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command
-__buf__     | Must point to an previously by `nk_convert` filled out vertex draw command buffer
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-Returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer
-#### nk_draw_foreach
-Iterates over each vertex draw command inside a vertex draw command buffer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_draw_foreach(cmd,ctx, b)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__cmd__     | `nk_draw_command`iterator set to NULL
-__buf__     | Must point to an previously by `nk_convert` filled out vertex draw command buffer
-__ctx__     | Must point to an previously initialized `nk_context` struct at the end of a frame
-### Window
-Windows are the main persistent state used inside nuklear and are life time
-controlled by simply "retouching" (i.e. calling) each window each frame.
-All widgets inside nuklear can only be added inside the function pair `nk_begin_xxx`
-and `nk_end`. Calling any widgets outside these two functions will result in an
-assert in debug or no state change in release mode.<br /><br />
-Each window holds frame persistent state like position, size, flags, state tables,
-and some garbage collected internal persistent widget state. Each window
-is linked into a window stack list which determines the drawing and overlapping
-order. The topmost window thereby is the currently active window.<br /><br />
-To change window position inside the stack occurs either automatically by
-user input by being clicked on or programmatically by calling `nk_window_focus`.
-Windows by default are visible unless explicitly being defined with flag
-`NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag
-`NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling
-`nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.<br /><br />
-#### Usage
-To create and keep a window you have to call one of the two `nk_begin_xxx`
-functions to start window declarations and `nk_end` at the end. Furthermore it
-is recommended to check the return value of `nk_begin_xxx` and only process
-widgets inside the window if the value is not 0. Either way you have to call
-`nk_end` at the end of window declarations. Furthermore, do not attempt to
-nest `nk_begin_xxx` calls which will hopefully result in an assert or if not
-in a segmentation fault.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-if (nk_begin_xxx(...) {
-    // [... widgets ...]
-}
-nk_end(ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In the grand concept window and widget declarations need to occur after input
-handling and before drawing to screen. Not doing so can result in higher
-latency or at worst invalid behavior. Furthermore make sure that `nk_clear`
-is called at the end of the frame. While nuklear's default platform backends
-already call `nk_clear` for you if you write your own backend not calling
-`nk_clear` can cause asserts or even worse undefined behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    Event evt;
-    nk_input_begin(&ctx);
-    while (GetEvent(&evt)) {
-        if (evt.type == MOUSE_MOVE)
-            nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-        else if (evt.type == [...]) {
-            nk_input_xxx(...);
-        }
-    }
-    nk_input_end(&ctx);
-    if (nk_begin_xxx(...) {
-        //[...]
-    }
-    nk_end(ctx);
-    const struct nk_command *cmd = 0;
-    nk_foreach(cmd, &ctx) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case //...:
-        //[...]
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function                            | Description
-------------------------------------|----------------------------------------
-nk_begin                            | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed
-nk_begin_titled                     | Extended window start with separated title and identifier to allow multiple windows with same name but not title
-nk_end                              | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup
-nk_window_find                      | Finds and returns the window with give name
-nk_window_get_bounds                | Returns a rectangle with screen position and size of the currently processed window.
-nk_window_get_position              | Returns the position of the currently processed window
-nk_window_get_size                  | Returns the size with width and height of the currently processed window
-nk_window_get_width                 | Returns the width of the currently processed window
-nk_window_get_height                | Returns the height of the currently processed window
-nk_window_get_panel                 | Returns the underlying panel which contains all processing state of the current window
-nk_window_get_content_region        | Returns the position and size of the currently visible and non-clipped space inside the currently processed window
-nk_window_get_content_region_min    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
-nk_window_get_content_region_max    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window
-nk_window_get_content_region_size   | Returns the size of the currently visible and non-clipped space inside the currently processed window
-nk_window_get_canvas                | Returns the draw command buffer. Can be used to draw custom widgets
-nk_window_get_scroll                | Gets the scroll offset of the current window
-nk_window_has_focus                 | Returns if the currently processed window is currently active
-nk_window_is_collapsed              | Returns if the window with given name is currently minimized/collapsed
-nk_window_is_closed                 | Returns if the currently processed window was closed
-nk_window_is_hidden                 | Returns if the currently processed window was hidden
-nk_window_is_active                 | Same as nk_window_has_focus for some reason
-nk_window_is_hovered                | Returns if the currently processed window is currently being hovered by mouse
-nk_window_is_any_hovered            | Return if any window currently hovered
-nk_item_is_any_active               | Returns if any window or widgets is currently hovered or active
-nk_window_set_bounds                | Updates position and size of the currently processed window
-nk_window_set_position              | Updates position of the currently process window
-nk_window_set_size                  | Updates the size of the currently processed window
-nk_window_set_focus                 | Set the currently processed window as active window
-nk_window_set_scroll                | Sets the scroll offset of the current window
-nk_window_close                     | Closes the window with given window name which deletes the window at the end of the frame
-nk_window_collapse                  | Collapses the window with given window name
-nk_window_collapse_if               | Collapses the window with given window name if the given condition was met
-nk_window_show                      | Hides a visible or reshows a hidden window
-nk_window_show_if                   | Hides/shows a window depending on condition
-#### nk_panel_flags
-Flag                        | Description
-----------------------------|----------------------------------------
-NK_WINDOW_BORDER            | Draws a border around the window to visually separate window from the background
-NK_WINDOW_MOVABLE           | The movable flag indicates that a window can be moved by user input or by dragging the window header
-NK_WINDOW_SCALABLE          | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window
-NK_WINDOW_CLOSABLE          | Adds a closable icon into the header
-NK_WINDOW_MINIMIZABLE       | Adds a minimize icon into the header
-NK_WINDOW_NO_SCROLLBAR      | Removes the scrollbar from the window
-NK_WINDOW_TITLE             | Forces a header at the top at the window showing the title
-NK_WINDOW_SCROLL_AUTO_HIDE  | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame
-NK_WINDOW_BACKGROUND        | Always keep window in the background
-NK_WINDOW_SCALE_LEFT        | Puts window scaler in the left-bottom corner instead right-bottom
-NK_WINDOW_NO_INPUT          | Prevents window of scaling, moving or getting focus
-#### nk_collapse_states
-State           | Description
-----------------|-----------------------------------------------------------
-__NK_MINIMIZED__| UI section is collapsed and not visible until maximized
-__NK_MAXIMIZED__| UI section is extended and visible until minimized
-<br /><br />
-#### nk_begin
-Starts a new window; needs to be called every frame for every
-window (unless hidden) or otherwise the window gets removed
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__title__   | Window title and identifier. Needs to be persistent over frames to identify the window
-__bounds__  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
-__flags__   | Window flags defined in the nk_panel_flags section with a number of different window behaviors
-Returns `true(1)` if the window can be filled up with widgets from this point
-until `nk_end` or `false(0)` otherwise for example if minimized
-#### nk_begin_titled
-Extended window start with separated title and identifier to allow multiple
-windows with same title but not name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Window identifier. Needs to be persistent over frames to identify the window
-__title__   | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set
-__bounds__  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame
-__flags__   | Window flags defined in the nk_panel_flags section with a number of different window behaviors
-Returns `true(1)` if the window can be filled up with widgets from this point
-until `nk_end` or `false(0)` otherwise for example if minimized
-#### nk_end
-Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup.
-All widget calls after this functions will result in asserts or no state changes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_end(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-#### nk_window_find
-Finds and returns a window from passed name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_window *nk_window_find(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Window identifier
-Returns a `nk_window` struct pointing to the identified window or NULL if
-no window with the given name was found
-#### nk_window_get_bounds
-Returns a rectangle with screen position and size of the currently processed window
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns a `nk_rect` struct with window upper left window position and size
-#### nk_window_get_position
-Returns the position of the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns a `nk_vec2` struct with window upper left position
-#### nk_window_get_size
-Returns the size with width and height of the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns a `nk_vec2` struct with window width and height
-#### nk_window_get_width
-Returns the width of the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-float nk_window_get_width(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns the current window width
-#### nk_window_get_height
-Returns the height of the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-float nk_window_get_height(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns the current window height
-#### nk_window_get_panel
-Returns the underlying panel which contains all processing state of the current window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-!!! WARNING
-    Do not keep the returned panel pointer around, it is only valid until `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_panel* nk_window_get_panel(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns a pointer to window internal `nk_panel` state.
-#### nk_window_get_content_region
-Returns the position and size of the currently visible and non-clipped space
-inside the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_window_get_content_region(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `nk_rect` struct with screen position and size (no scrollbar offset)
-of the visible space inside the current window
-#### nk_window_get_content_region_min
-Returns the upper left position of the currently visible and non-clipped
-space inside the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-returns `nk_vec2` struct with  upper left screen position (no scrollbar offset)
-of the visible space inside the current window
-#### nk_window_get_content_region_max
-Returns the lower right screen position of the currently visible and
-non-clipped space inside the currently processed window.
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `nk_vec2` struct with lower right screen position (no scrollbar offset)
-of the visible space inside the current window
-#### nk_window_get_content_region_size
-Returns the size of the currently visible and non-clipped space inside the
-currently processed window
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `nk_vec2` struct with size the visible space inside the current window
-#### nk_window_get_canvas
-Returns the draw command buffer. Can be used to draw custom widgets
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-!!! WARNING
-    Do not keep the returned command buffer pointer around it is only valid until `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns a pointer to window internal `nk_command_buffer` struct used as
-drawing canvas. Can be used to do custom drawing.
-#### nk_window_get_scroll
-Gets the scroll offset for the current window
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter    | Description
--------------|-----------------------------------------------------------
-__ctx__      | Must point to an previously initialized `nk_context` struct
-__offset_x__ | A pointer to the x offset output (or NULL to ignore)
-__offset_y__ | A pointer to the y offset output (or NULL to ignore)
-#### nk_window_has_focus
-Returns if the currently processed window is currently active
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_has_focus(const struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `false(0)` if current window is not active or `true(1)` if it is
-#### nk_window_is_hovered
-Return if the current window is being hovered
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_hovered(struct nk_context *ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `true(1)` if current window is hovered or `false(0)` otherwise
-#### nk_window_is_collapsed
-Returns if the window with given name is currently minimized/collapsed
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_collapsed(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of window you want to check if it is collapsed
-Returns `true(1)` if current window is minimized and `false(0)` if window not
-found or is not minimized
-#### nk_window_is_closed
-Returns if the window with given name was closed by calling `nk_close`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_closed(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of window you want to check if it is closed
-Returns `true(1)` if current window was closed or `false(0)` window not found or not closed
-#### nk_window_is_hidden
-Returns if the window with given name is hidden
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_hidden(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of window you want to check if it is hidden
-Returns `true(1)` if current window is hidden or `false(0)` window not found or visible
-#### nk_window_is_active
-Same as nk_window_has_focus for some reason
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_active(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of window you want to check if it is active
-Returns `true(1)` if current window is active or `false(0)` window not found or not active
-#### nk_window_is_any_hovered
-Returns if the any window is being hovered
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_window_is_any_hovered(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `true(1)` if any window is hovered or `false(0)` otherwise
-#### nk_item_is_any_active
-Returns if the any window is being hovered or any widget is currently active.
-Can be used to decide if input should be processed by UI or your specific input handling.
-Example could be UI and 3D camera to move inside a 3D space.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_item_is_any_active(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-Returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise
-#### nk_window_set_bounds
-Updates position and size of window with passed in name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to modify both position and size
-__bounds__  | Must point to a `nk_rect` struct with the new position and size
-#### nk_window_set_position
-Updates position of window with passed name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to modify both position
-__pos__     | Must point to a `nk_vec2` struct with the new position
-#### nk_window_set_size
-Updates size of window with passed in name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to modify both window size
-__size__    | Must point to a `nk_vec2` struct with new window size
-#### nk_window_set_focus
-Sets the window with given name as active
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_set_focus(struct nk_context*, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to set focus on
-#### nk_window_set_scroll
-Sets the scroll offset for the current window
-!!! WARNING
-    Only call this function between calls `nk_begin_xxx` and `nk_end`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter    | Description
--------------|-----------------------------------------------------------
-__ctx__      | Must point to an previously initialized `nk_context` struct
-__offset_x__ | The x offset to scroll to
-__offset_y__ | The y offset to scroll to
-#### nk_window_close
-Closes a window and marks it for being freed at the end of the frame
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_close(struct nk_context *ctx, const char *name);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to close
-#### nk_window_collapse
-Updates collapse state of a window with given name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to close
-__state__   | value out of nk_collapse_states section
-#### nk_window_collapse_if
-Updates collapse state of a window with given name if given condition is met
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to either collapse or maximize
-__state__   | value out of nk_collapse_states section the window should be put into
-__cond__    | condition that has to be met to actually commit the collapse state change
-#### nk_window_show
-updates visibility state of a window with given name
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_show(struct nk_context*, const char *name, enum nk_show_states);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to either collapse or maximize
-__state__   | state with either visible or hidden to modify the window with
-#### nk_window_show_if
-Updates visibility state of a window with given name if a given condition is met
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__name__    | Identifier of the window to either hide or show
-__state__   | state with either visible or hidden to modify the window with
-__cond__    | condition that has to be met to actually commit the visibility state change
-### Layouting
-Layouting in general describes placing widget inside a window with position and size.
-While in this particular implementation there are five different APIs for layouting
-each with different trade offs between control and ease of use. <br /><br />
-All layouting methods in this library are based around the concept of a row.
-A row has a height the window content grows by and a number of columns and each
-layouting method specifies how each widget is placed inside the row.
-After a row has been allocated by calling a layouting functions and then
-filled with widgets will advance an internal pointer over the allocated row. <br /><br />
-To actually define a layout you just call the appropriate layouting function
-and each subsequent widget call will place the widget as specified. Important
-here is that if you define more widgets then columns defined inside the layout
-functions it will allocate the next row without you having to make another layouting <br /><br />
-call.
-Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API
-is that you have to define the row height for each. However the row height
-often depends on the height of the font. <br /><br />
-To fix that internally nuklear uses a minimum row height that is set to the
-height plus padding of currently active font and overwrites the row height
-value if zero. <br /><br />
-If you manually want to change the minimum row height then
-use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to
-reset it back to be derived from font height. <br /><br />
-Also if you change the font in nuklear it will automatically change the minimum
-row height for you and. This means if you change the font but still want
-a minimum row height smaller than the font you have to repush your value. <br /><br />
-For actually more advanced UI I would even recommend using the `nk_layout_space_xxx`
-layouting method in combination with a cassowary constraint solver (there are
-some versions on github with permissive license model) to take over all control over widget
-layouting yourself. However for quick and dirty layouting using all the other layouting
-functions should be fine.
-#### Usage
-1.  __nk_layout_row_dynamic__<br /><br />
-    The easiest layouting function is `nk_layout_row_dynamic`. It provides each
-    widgets with same horizontal space inside the row and dynamically grows
-    if the owning window grows in width. So the number of columns dictates
-    the size of each widget dynamically by formula:
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    widget_width = (window_width - padding - spacing) * (1/column_count)
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Just like all other layouting APIs if you define more widget than columns this
-    library will allocate a new row and keep all layouting parameters previously
-    defined.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // first row with height: 30 composed of two widgets
-        nk_layout_row_dynamic(&ctx, 30, 2);
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // second row with same parameter as defined above
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // third row uses 0 for height which will use auto layouting
-        nk_layout_row_dynamic(&ctx, 0, 2);
-        nk_widget(...);
-        nk_widget(...);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-2.  __nk_layout_row_static__<br /><br />
-    Another easy layouting function is `nk_layout_row_static`. It provides each
-    widget with same horizontal pixel width inside the row and does not grow
-    if the owning window scales smaller or bigger.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // first row with height: 30 composed of two widgets with width: 80
-        nk_layout_row_static(&ctx, 30, 80, 2);
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // second row with same parameter as defined above
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // third row uses 0 for height which will use auto layouting
-        nk_layout_row_static(&ctx, 0, 80, 2);
-        nk_widget(...);
-        nk_widget(...);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-3.  __nk_layout_row_xxx__<br /><br />
-    A little bit more advanced layouting API are functions `nk_layout_row_begin`,
-    `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly
-    specify each column pixel or window ratio in a row. It supports either
-    directly setting per column pixel width or widget window ratio but not
-    both. Furthermore it is a immediate mode API so each value is directly
-    pushed before calling a widget. Therefore the layout is not automatically
-    repeating like the last two layouting functions.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // first row with height: 25 composed of two widgets with width 60 and 40
-        nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
-        nk_layout_row_push(ctx, 60);
-        nk_widget(...);
-        nk_layout_row_push(ctx, 40);
-        nk_widget(...);
-        nk_layout_row_end(ctx);
-        //
-        // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75
-        nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2);
-        nk_layout_row_push(ctx, 0.25f);
-        nk_widget(...);
-        nk_layout_row_push(ctx, 0.75f);
-        nk_widget(...);
-        nk_layout_row_end(ctx);
-        //
-        // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75
-        nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2);
-        nk_layout_row_push(ctx, 0.25f);
-        nk_widget(...);
-        nk_layout_row_push(ctx, 0.75f);
-        nk_widget(...);
-        nk_layout_row_end(ctx);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-4.  __nk_layout_row__<br /><br />
-    The array counterpart to API nk_layout_row_xxx is the single nk_layout_row
-    functions. Instead of pushing either pixel or window ratio for every widget
-    it allows to define it by array. The trade of for less control is that
-    `nk_layout_row` is automatically repeating. Otherwise the behavior is the
-    same.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // two rows with height: 30 composed of two widgets with width 60 and 40
-        const float size[] = {60,40};
-        nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75
-        const float ratio[] = {0.25, 0.75};
-        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-        //
-        // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75
-        const float ratio[] = {0.25, 0.75};
-        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-5.  __nk_layout_row_template_xxx__<br /><br />
-    The most complex and second most flexible API is a simplified flexbox version without
-    line wrapping and weights for dynamic widgets. It is an immediate mode API but
-    unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called
-    before calling the templated widgets.
-    The row template layout has three different per widget size specifier. The first
-    one is the `nk_layout_row_template_push_static`  with fixed widget pixel width.
-    They do not grow if the row grows and will always stay the same.
-    The second size specifier is `nk_layout_row_template_push_variable`
-    which defines a minimum widget size but it also can grow if more space is available
-    not taken by other widgets.
-    Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic`
-    which are completely flexible and unlike variable widgets can even shrink
-    to zero if not enough space is provided.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // two rows with height: 30 composed of three widgets
-        nk_layout_row_template_begin(ctx, 30);
-        nk_layout_row_template_push_dynamic(ctx);
-        nk_layout_row_template_push_variable(ctx, 80);
-        nk_layout_row_template_push_static(ctx, 80);
-        nk_layout_row_template_end(ctx);
-        //
-        // first row
-        nk_widget(...); // dynamic widget can go to zero if not enough space
-        nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space
-        nk_widget(...); // static widget with fixed 80 pixel width
-        //
-        // second row same layout
-        nk_widget(...);
-        nk_widget(...);
-        nk_widget(...);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-6.  __nk_layout_space_xxx__<br /><br />
-    Finally the most flexible API directly allows you to place widgets inside the
-    window. The space layout API is an immediate mode API which does not support
-    row auto repeat and directly sets position and size of a widget. Position
-    and size hereby can be either specified as ratio of allocated space or
-    allocated space local position and pixel size. Since this API is quite
-    powerful there are a number of utility functions to get the available space
-    and convert between local allocated space and screen space.
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-    if (nk_begin_xxx(...) {
-        // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)
-        nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX);
-        nk_layout_space_push(ctx, nk_rect(0,0,150,200));
-        nk_widget(...);
-        nk_layout_space_push(ctx, nk_rect(200,200,100,200));
-        nk_widget(...);
-        nk_layout_space_end(ctx);
-        //
-        // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)
-        nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX);
-        nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1));
-        nk_widget(...);
-        nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1));
-        nk_widget(...);
-    }
-    nk_end(...);
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function                                | Description
-----------------------------------------|------------------------------------
-nk_layout_set_min_row_height            | Set the currently used minimum row height to a specified value
-nk_layout_reset_min_row_height          | Resets the currently used minimum row height to font height
-nk_layout_widget_bounds                 | Calculates current width a static layout row can fit inside a window
-nk_layout_ratio_from_pixel              | Utility functions to calculate window ratio from pixel size
-nk_layout_row_dynamic                   | Current layout is divided into n same sized growing columns
-nk_layout_row_static                    | Current layout is divided into n same fixed sized columns
-nk_layout_row_begin                     | Starts a new row with given height and number of columns
-nk_layout_row_push                      | Pushes another column with given size or window ratio
-nk_layout_row_end                       | Finished previously started row
-nk_layout_row                           | Specifies row columns in array as either window ratio or size
-nk_layout_row_template_begin            | Begins the row template declaration
-nk_layout_row_template_push_dynamic     | Adds a dynamic column that dynamically grows and can go to zero if not enough space
-nk_layout_row_template_push_variable    | Adds a variable column that dynamically grows but does not shrink below specified pixel width
-nk_layout_row_template_push_static      | Adds a static column that does not grow and will always have the same size
-nk_layout_row_template_end              | Marks the end of the row template
-nk_layout_space_begin                   | Begins a new layouting space that allows to specify each widgets position and size
-nk_layout_space_push                    | Pushes position and size of the next widget in own coordinate space either as pixel or ratio
-nk_layout_space_end                     | Marks the end of the layouting space
-nk_layout_space_bounds                  | Callable after nk_layout_space_begin and returns total space allocated
-nk_layout_space_to_screen               | Converts vector from nk_layout_space coordinate space into screen space
-nk_layout_space_to_local                | Converts vector from screen space into nk_layout_space coordinates
-nk_layout_space_rect_to_screen          | Converts rectangle from nk_layout_space coordinate space into screen space
-nk_layout_space_rect_to_local           | Converts rectangle from screen space into nk_layout_space coordinates
-#### nk_layout_set_min_row_height
-Sets the currently used minimum row height.
-!!! WARNING
-    The passed height needs to include both your preferred row height
-    as well as padding. No internal padding is added.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_set_min_row_height(struct nk_context*, float height);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__height__  | New minimum row height to be used for auto generating the row height
-#### nk_layout_reset_min_row_height
-Reset the currently used minimum row height back to `font_height + text_padding + padding`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_reset_min_row_height(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-#### nk_layout_widget_bounds
-Returns the width of the next row allocate by one of the layouting functions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_layout_widget_bounds(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-Return `nk_rect` with both position and size of the next row
-#### nk_layout_ratio_from_pixel
-Utility functions to calculate window ratio from pixel size
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__pixel__   | Pixel_width to convert to window ratio
-Returns `nk_rect` with both position and size of the next row
-#### nk_layout_row_dynamic
-Sets current row layout to share horizontal space
-between @cols number of widgets evenly. Once called all subsequent widget
-calls greater than @cols will allocate a new row with same layout.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__height__  | Holds height of each widget in row or zero for auto layouting
-__columns__ | Number of widget inside row
-#### nk_layout_row_static
-Sets current row layout to fill @cols number of widgets
-in row with same @item_width horizontal size. Once called all subsequent widget
-calls greater than @cols will allocate a new row with same layout.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__height__  | Holds height of each widget in row or zero for auto layouting
-__width__   | Holds pixel width of each widget in the row
-__columns__ | Number of widget inside row
-#### nk_layout_row_begin
-Starts a new dynamic or fixed row with given height and columns.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__fmt__     | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
-__height__  | holds height of each widget in row or zero for auto layouting
-__columns__ | Number of widget inside row
-#### nk_layout_row_push
-Specifies either window ratio or width of a single column
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_push(struct nk_context*, float value);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__value__   | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call
-#### nk_layout_row_end
-Finished previously started row
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_end(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-#### nk_layout_row
-Specifies row columns in array as either window ratio or size
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__fmt__     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
-__height__  | Holds height of each widget in row or zero for auto layouting
-__columns__ | Number of widget inside row
-#### nk_layout_row_template_begin
-Begins the row template declaration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_template_begin(struct nk_context*, float row_height);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__height__  | Holds height of each widget in row or zero for auto layouting
-#### nk_layout_row_template_push_dynamic
-Adds a dynamic column that dynamically grows and can go to zero if not enough space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_template_push_dynamic(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__height__  | Holds height of each widget in row or zero for auto layouting
-#### nk_layout_row_template_push_variable
-Adds a variable column that dynamically grows but does not shrink below specified pixel width
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_template_push_variable(struct nk_context*, float min_width);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__width__   | Holds the minimum pixel width the next column must always be
-#### nk_layout_row_template_push_static
-Adds a static column that does not grow and will always have the same size
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_template_push_static(struct nk_context*, float width);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__width__   | Holds the absolute pixel width value the next column must be
-#### nk_layout_row_template_end
-Marks the end of the row template
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_row_template_end(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-#### nk_layout_space_begin
-Begins a new layouting space that allows to specify each widgets position and size.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`
-__fmt__     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns
-__height__  | Holds height of each widget in row or zero for auto layouting
-__columns__ | Number of widgets inside row
-#### nk_layout_space_push
-Pushes position and size of the next widget in own coordinate space either as pixel or ratio
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-__bounds__  | Position and size in laoyut space local coordinates
-#### nk_layout_space_end
-Marks the end of the layout space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_layout_space_end(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-#### nk_layout_space_bounds
-Utility function to calculate total space allocated for `nk_layout_space`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_layout_space_bounds(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-Returns `nk_rect` holding the total space allocated
-#### nk_layout_space_to_screen
-Converts vector from nk_layout_space coordinate space into screen space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-__vec__     | Position to convert from layout space into screen coordinate space
-Returns transformed `nk_vec2` in screen space coordinates
-#### nk_layout_space_to_local
-Converts vector from layout space into screen space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-__vec__     | Position to convert from screen space into layout coordinate space
-Returns transformed `nk_vec2` in layout space coordinates
-#### nk_layout_space_rect_to_screen
-Converts rectangle from screen space into layout space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-__bounds__  | Rectangle to convert from layout space into screen space
-Returns transformed `nk_rect` in screen space coordinates
-#### nk_layout_space_rect_to_local
-Converts rectangle from layout space into screen space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-__bounds__  | Rectangle to convert from layout space into screen space
-Returns transformed `nk_rect` in layout space coordinates
-#### nk_spacer
-Spacer is a dummy widget that consumes space as usual but doesn't draw anything
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_spacer(struct nk_context* );
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`
-### Groups
-Groups are basically windows inside windows. They allow to subdivide space
-in a window to layout widgets as a group. Almost all more complex widget
-layouting requirements can be solved using groups and basic layouting
-fuctionality. Groups just like windows are identified by an unique name and
-internally keep track of scrollbar offsets by default. However additional
-versions are provided to directly manage the scrollbar.
-#### Usage
-To create a group you have to call one of the three `nk_group_begin_xxx`
-functions to start group declarations and `nk_group_end` at the end. Furthermore it
-is required to check the return value of `nk_group_begin_xxx` and only process
-widgets inside the window if the value is not 0.
-Nesting groups is possible and even encouraged since many layouting schemes
-can only be achieved by nesting. Groups, unlike windows, need `nk_group_end`
-to be only called if the corresponding `nk_group_begin_xxx` call does not return 0:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-if (nk_group_begin_xxx(ctx, ...) {
-    // [... widgets ...]
-    nk_group_end(ctx);
-}
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In the grand concept groups can be called after starting a window
-with `nk_begin_xxx` and before calling `nk_end`:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    // Input
-    Event evt;
-    nk_input_begin(&ctx);
-    while (GetEvent(&evt)) {
-        if (evt.type == MOUSE_MOVE)
-            nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-        else if (evt.type == [...]) {
-            nk_input_xxx(...);
-        }
-    }
-    nk_input_end(&ctx);
-    //
-    // Window
-    if (nk_begin_xxx(...) {
-        // [...widgets...]
-        nk_layout_row_dynamic(...);
-        if (nk_group_begin_xxx(ctx, ...) {
-            //[... widgets ...]
-            nk_group_end(ctx);
-        }
-    }
-    nk_end(ctx);
-    //
-    // Draw
-    const struct nk_command *cmd = 0;
-    nk_foreach(cmd, &ctx) {
-    switch (cmd->type) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case ...:
-        // [...]
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function                        | Description
---------------------------------|-------------------------------------------
-nk_group_begin                  | Start a new group with internal scrollbar handling
-nk_group_begin_titled           | Start a new group with separated name and title and internal scrollbar handling
-nk_group_end                    | Ends a group. Should only be called if nk_group_begin returned non-zero
-nk_group_scrolled_offset_begin  | Start a new group with manual separated handling of scrollbar x- and y-offset
-nk_group_scrolled_begin         | Start a new group with manual scrollbar handling
-nk_group_scrolled_end           | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero
-nk_group_get_scroll             | Gets the scroll offset for the given group
-nk_group_set_scroll             | Sets the scroll offset for the given group
-#### nk_group_begin
-Starts a new widget group. Requires a previous layouting function to specify a pos/size.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__title__   | Must be an unique identifier for this group that is also used for the group header
-__flags__   | Window flags defined in the nk_panel_flags section with a number of different group behaviors
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_group_begin_titled
-Starts a new widget group. Requires a previous layouting function to specify a pos/size.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__id__      | Must be an unique identifier for this group
-__title__   | Group header title
-__flags__   | Window flags defined in the nk_panel_flags section with a number of different group behaviors
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_group_end
-Ends a widget group
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_group_end(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-#### nk_group_scrolled_offset_begin
-starts a new widget group. requires a previous layouting function to specify
-a size. Does not keep track of scrollbar.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__x_offset__| Scrollbar x-offset to offset all widgets inside the group horizontally.
-__y_offset__| Scrollbar y-offset to offset all widgets inside the group vertically
-__title__   | Window unique group title used to both identify and display in the group header
-__flags__   | Window flags from the nk_panel_flags section
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_group_scrolled_begin
-Starts a new widget group. requires a previous
-layouting function to specify a size. Does not keep track of scrollbar.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__off__     | Both x- and y- scroll offset. Allows for manual scrollbar control
-__title__   | Window unique group title used to both identify and display in the group header
-__flags__   | Window flags from nk_panel_flags section
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_group_scrolled_end
-Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_group_scrolled_end(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-#### nk_group_get_scroll
-Gets the scroll position of the given group.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter    | Description
--------------|-----------------------------------------------------------
-__ctx__      | Must point to an previously initialized `nk_context` struct
-__id__       | The id of the group to get the scroll position of
-__x_offset__ | A pointer to the x offset output (or NULL to ignore)
-__y_offset__ | A pointer to the y offset output (or NULL to ignore)
-#### nk_group_set_scroll
-Sets the scroll position of the given group.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter    | Description
--------------|-----------------------------------------------------------
-__ctx__      | Must point to an previously initialized `nk_context` struct
-__id__       | The id of the group to scroll
-__x_offset__ | The x offset to scroll to
-__y_offset__ | The y offset to scroll to
-### Tree
-Trees represent two different concept. First the concept of a collapsible
-UI section that can be either in a hidden or visible state. They allow the UI
-user to selectively minimize the current set of visible UI to comprehend.
-The second concept are tree widgets for visual UI representation of trees.<br /><br />
-Trees thereby can be nested for tree representations and multiple nested
-collapsible UI sections. All trees are started by calling of the
-`nk_tree_xxx_push_tree` functions and ended by calling one of the
-`nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label
-and optionally an image to be displayed and the initial collapse state from
-the nk_collapse_states section.<br /><br />
-The runtime state of the tree is either stored outside the library by the caller
-or inside which requires a unique ID. The unique ID can either be generated
-automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`,
-by `__FILE__` and a user provided ID generated for example by loop index with
-function `nk_tree_push_id` or completely provided from outside by user with
-function `nk_tree_push_hashed`.
-#### Usage
-To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx`
-functions to start a collapsible UI section and `nk_tree_xxx_pop` to mark the
-end.
-Each starting function will either return `false(0)` if the tree is collapsed
-or hidden and therefore does not need to be filled with content or `true(1)`
-if visible and required to be filled.
-!!! Note
-    The tree header does not require and layouting function and instead
-    calculates a auto height based on the currently used font size
-The tree ending functions only need to be called if the tree content is
-actually visible. So make sure the tree push function is guarded by `if`
-and the pop call is only taken if the tree is visible.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-if (nk_tree_push(ctx, NK_TREE_TAB, "Tree", NK_MINIMIZED)) {
-    nk_layout_row_dynamic(...);
-    nk_widget(...);
-    nk_tree_pop(ctx);
-}
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function                    | Description
-----------------------------|-------------------------------------------
-nk_tree_push                | Start a collapsible UI section with internal state management
-nk_tree_push_id             | Start a collapsible UI section with internal state management callable in a look
-nk_tree_push_hashed         | Start a collapsible UI section with internal state management with full control over internal unique ID use to store state
-nk_tree_image_push          | Start a collapsible UI section with image and label header
-nk_tree_image_push_id       | Start a collapsible UI section with image and label header and internal state management callable in a look
-nk_tree_image_push_hashed   | Start a collapsible UI section with image and label header and internal state management with full control over internal unique ID use to store state
-nk_tree_pop                 | Ends a collapsible UI section
-nk_tree_state_push          | Start a collapsible UI section with external state management
-nk_tree_state_image_push    | Start a collapsible UI section with image and label header and external state management
-nk_tree_state_pop           | Ends a collapsabale UI section
-#### nk_tree_type
-Flag            | Description
-----------------|----------------------------------------
-NK_TREE_NODE    | Highlighted tree header to mark a collapsible UI section
-NK_TREE_TAB     | Non-highlighted tree header closer to tree representations
-#### nk_tree_push
-Starts a collapsible UI section with internal state management
-!!! WARNING
-    To keep track of the runtime tree collapsible state this function uses
-    defines `__FILE__` and `__LINE__` to generate a unique ID. If you want
-    to call this function in a loop please use `nk_tree_push_id` or
-    `nk_tree_push_hashed` instead.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_tree_push(ctx, type, title, state)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_push_id
-Starts a collapsible UI section with internal state management callable in a look
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_tree_push_id(ctx, type, title, state, id)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-__id__      | Loop counter index if this function is called in a loop
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_push_hashed
-Start a collapsible UI section with internal state management with full
-control over internal unique ID used to store state
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-__hash__    | Memory block or string to generate the ID from
-__len__     | Size of passed memory block or string in __hash__
-__seed__    | Seeding value if this function is called in a loop or default to `0`
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_image_push
-Start a collapsible UI section with image and label header
-!!! WARNING
-    To keep track of the runtime tree collapsible state this function uses
-    defines `__FILE__` and `__LINE__` to generate a unique ID. If you want
-    to call this function in a loop please use `nk_tree_image_push_id` or
-    `nk_tree_image_push_hashed` instead.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_tree_image_push(ctx, type, img, title, state)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__img__     | Image to display inside the header on the left of the label
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_image_push_id
-Start a collapsible UI section with image and label header and internal state
-management callable in a look
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-#define nk_tree_image_push_id(ctx, type, img, title, state, id)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__img__     | Image to display inside the header on the left of the label
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-__id__      | Loop counter index if this function is called in a loop
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_image_push_hashed
-Start a collapsible UI section with internal state management with full
-control over internal unique ID used to store state
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__img__     | Image to display inside the header on the left of the label
-__title__   | Label printed in the tree header
-__state__   | Initial tree state value out of nk_collapse_states
-__hash__    | Memory block or string to generate the ID from
-__len__     | Size of passed memory block or string in __hash__
-__seed__    | Seeding value if this function is called in a loop or default to `0`
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_pop
-Ends a collapsabale UI section
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_tree_pop(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`
-#### nk_tree_state_push
-Start a collapsible UI section with external state management
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__title__   | Label printed in the tree header
-__state__   | Persistent state to update
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_state_image_push
-Start a collapsible UI section with image and label header and external state management
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`
-__img__     | Image to display inside the header on the left of the label
-__type__    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node
-__title__   | Label printed in the tree header
-__state__   | Persistent state to update
-Returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise
-#### nk_tree_state_pop
-Ends a collapsabale UI section
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_tree_state_pop(struct nk_context*);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter   | Description
-------------|-----------------------------------------------------------
-__ctx__     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`
-### Properties
-Properties are the main value modification widgets in Nuklear. Changing a value
-can be achieved by dragging, adding/removing incremental steps on button click
-or by directly typing a number.
-#### Usage
-Each property requires a unique name for identification that is also used for
-displaying a label. If you want to use the same name multiple times make sure
-add a '#' before your name. The '#' will not be shown but will generate a
-unique ID. Each property also takes in a minimum and maximum value. If you want
-to make use of the complete number range of a type just use the provided
-type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for
-`nk_property_int` and `nk_propertyi`. In additional each property takes in
-a increment value that will be added or subtracted if either the increment
-decrement button is clicked. Finally there is a value for increment per pixel
-dragged that is added or subtracted from the value.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-int value = 0;
-struct nk_context ctx;
-nk_init_xxx(&ctx, ...);
-while (1) {
-    // Input
-    Event evt;
-    nk_input_begin(&ctx);
-    while (GetEvent(&evt)) {
-        if (evt.type == MOUSE_MOVE)
-            nk_input_motion(&ctx, evt.motion.x, evt.motion.y);
-        else if (evt.type == [...]) {
-            nk_input_xxx(...);
-        }
-    }
-    nk_input_end(&ctx);
-    //
-    // Window
-    if (nk_begin_xxx(...) {
-        // Property
-        nk_layout_row_dynamic(...);
-        nk_property_int(ctx, "ID", INT_MIN, &value, INT_MAX, 1, 1);
-    }
-    nk_end(ctx);
-    //
-    // Draw
-    const struct nk_command *cmd = 0;
-    nk_foreach(cmd, &ctx) {
-    switch (cmd->type) {
-    case NK_COMMAND_LINE:
-        your_draw_line_function(...)
-        break;
-    case NK_COMMAND_RECT
-        your_draw_rect_function(...)
-        break;
-    case ...:
-        // [...]
-    }
-    nk_clear(&ctx);
-}
-nk_free(&ctx);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#### Reference
-Function            | Description
---------------------|-------------------------------------------
-nk_property_int     | Integer property directly modifying a passed in value
-nk_property_float   | Float property directly modifying a passed in value
-nk_property_double  | Double property directly modifying a passed in value
-nk_propertyi        | Integer property returning the modified int value
-nk_propertyf        | Float property returning the modified float value
-nk_propertyd        | Double property returning the modified double value
-#### nk_property_int
-Integer property directly modifying a passed in value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Integer pointer to be modified
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-#### nk_property_float
-Float property directly modifying a passed in value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Float pointer to be modified
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-#### nk_property_double
-Double property directly modifying a passed in value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-void nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Double pointer to be modified
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-#### nk_propertyi
-Integer property modifying a passed in value and returning the new value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Current integer value to be modified and returned
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-Returns the new modified integer value
-#### nk_propertyf
-Float property modifying a passed in value and returning the new value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Current float value to be modified and returned
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-Returns the new modified float value
-#### nk_propertyd
-Float property modifying a passed in value and returning the new value
-!!! WARNING
-    To generate a unique property ID using the same label make sure to insert
-    a `#` at the beginning. It will not be shown but guarantees correct behavior.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel);
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Parameter           | Description
---------------------|-----------------------------------------------------------
-__ctx__             | Must point to an previously initialized `nk_context` struct after calling a layouting function
-__name__            | String used both as a label as well as a unique identifier
-__min__             | Minimum value not allowed to be underflown
-__val__             | Current double value to be modified and returned
-__max__             | Maximum value not allowed to be overflown
-__step__            | Increment added and subtracted on increment and decrement button
-__inc_per_pixel__   | Value per pixel added or subtracted on dragging
-Returns the new modified double value
-### Font
-Font handling in this library was designed to be quite customizable and lets
-you decide what you want to use and what you want to provide. There are three
-different ways to use the font atlas. The first two will use your font
-handling scheme and only requires essential data to run nuklear. The next
-slightly more advanced features is font handling with vertex buffer output.
-Finally the most complex API wise is using nuklear's font baking API.
-#### Using your own implementation without vertex buffer output
-
-So first up the easiest way to do font handling is by just providing a
-`nk_user_font` struct which only requires the height in pixel of the used
-font and a callback to calculate the width of a string. This way of handling
-fonts is best fitted for using the normal draw shape command API where you
-do all the text drawing yourself and the library does not require any kind
-of deeper knowledge about which font handling mechanism you use.
-IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist
-over the complete life time! I know this sucks but it is currently the only
-way to switch between fonts.
-```c
-    float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
-    {
-        your_font_type *type = handle.ptr;
-        float text_width = ...;
-        return text_width;
-    }
-    struct nk_user_font font;
-    font.userdata.ptr = &your_font_class_or_struct;
-    font.height = your_font_height;
-    font.width = your_text_width_calculation;
-
-    struct nk_context ctx;
-    nk_init_default(&ctx, &font);
-```
-#### Using your own implementation with vertex buffer output
-
-While the first approach works fine if you don't want to use the optional
-vertex buffer output it is not enough if you do. To get font handling working
-for these cases you have to provide two additional parameters inside the
-`nk_user_font`. First a texture atlas handle used to draw text as subimages
-of a bigger font atlas texture and a callback to query a character's glyph
-information (offset, size, ...). So it is still possible to provide your own
-font and use the vertex buffer output.
-```c
-    float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)
-    {
-        your_font_type *type = handle.ptr;
-        float text_width = ...;
-        return text_width;
-    }
-    void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)
-    {
-        your_font_type *type = handle.ptr;
-        glyph.width = ...;
-        glyph.height = ...;
-        glyph.xadvance = ...;
-        glyph.uv[0].x = ...;
-        glyph.uv[0].y = ...;
-        glyph.uv[1].x = ...;
-        glyph.uv[1].y = ...;
-        glyph.offset.x = ...;
-        glyph.offset.y = ...;
-    }
-
-    struct nk_user_font font;
-    font.userdata.ptr = &your_font_class_or_struct;
-    font.height = your_font_height;
-    font.width = your_text_width_calculation;
-    font.query = query_your_font_glyph;
-    font.texture.id = your_font_texture;
-
-    struct nk_context ctx;
-    nk_init_default(&ctx, &font);
-```
-#### Nuklear font baker
-
-The final approach if you do not have a font handling functionality or don't
-want to use it in this library is by using the optional font baker.
-The font baker APIs can be used to create a font plus font atlas texture
-and can be used with or without the vertex buffer output.
-
-It still uses the `nk_user_font` struct and the two different approaches
-previously stated still work. The font baker is not located inside
-`nk_context` like all other systems since it can be understood as more of
-an extension to nuklear and does not really depend on any `nk_context` state.
-
-Font baker need to be initialized first by one of the nk_font_atlas_init_xxx
-functions. If you don't care about memory just call the default version
-`nk_font_atlas_init_default` which will allocate all memory from the standard library.
-If you want to control memory allocation but you don't care if the allocated
-memory is temporary and therefore can be freed directly after the baking process
-is over or permanent you can call `nk_font_atlas_init`.
-
-After successfully initializing the font baker you can add Truetype(.ttf) fonts from
-different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`.
-functions. Adding font will permanently store each font, font config and ttf memory block(!)
-inside the font atlas and allows to reuse the font atlas. If you don't want to reuse
-the font baker by for example adding additional fonts you can call
-`nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end).
-
-As soon as you added all fonts you wanted you can now start the baking process
-for every selected glyph to image by calling `nk_font_atlas_bake`.
-The baking process returns image memory, width and height which can be used to
-either create your own image object or upload it to any graphics library.
-No matter which case you finally have to call `nk_font_atlas_end` which
-will free all temporary memory including the font atlas image so make sure
-you created our texture beforehand. `nk_font_atlas_end` requires a handle
-to your font texture or object and optionally fills a `struct nk_draw_null_texture`
-which can be used for the optional vertex output. If you don't want it just
-set the argument to `NULL`.
-
-At this point you are done and if you don't want to reuse the font atlas you
-can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration
-memory. Finally if you don't use the font atlas and any of it's fonts anymore
-you need to call `nk_font_atlas_clear` to free all memory still being used.
-
-```c
-    struct nk_font_atlas atlas;
-    nk_font_atlas_init_default(&atlas);
-    nk_font_atlas_begin(&atlas);
-    nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, 0);
-    nk_font *font2 = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font2.ttf", 16, 0);
-    const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32);
-    nk_font_atlas_end(&atlas, nk_handle_id(texture), 0);
-
-    struct nk_context ctx;
-    nk_init_default(&ctx, &font->handle);
-    while (1) {
-
-    }
-    nk_font_atlas_clear(&atlas);
-```
-The font baker API is probably the most complex API inside this library and
-I would suggest reading some of my examples `example/` to get a grip on how
-to use the font atlas. There are a number of details I left out. For example
-how to merge fonts, configure a font with `nk_font_config` to use other languages,
-use another texture coordinate format and a lot more:
-```c
-    struct nk_font_config cfg = nk_font_config(font_pixel_height);
-    cfg.merge_mode = nk_false or nk_true;
-    cfg.range = nk_font_korean_glyph_ranges();
-    cfg.coord_type = NK_COORD_PIXEL;
-    nk_font *font = nk_font_atlas_add_from_file(&atlas, "Path/To/Your/TTF_Font.ttf", 13, &cfg);
-```
-### Memory Buffer
-A basic (double)-buffer with linear allocation and resetting as only
-freeing policy. The buffer's main purpose is to control all memory management
-inside the GUI toolkit and still leave memory control as much as possible in
-the hand of the user while also making sure the library is easy to use if
-not as much control is needed.
-In general all memory inside this library can be provided from the user in
-three different ways.
-
-The first way and the one providing most control is by just passing a fixed
-size memory block. In this case all control lies in the hand of the user
-since he can exactly control where the memory comes from and how much memory
-the library should consume. Of course using the fixed size API removes the
-ability to automatically resize a buffer if not enough memory is provided so
-you have to take over the resizing. While being a fixed sized buffer sounds
-quite limiting, it is very effective in this library since the actual memory
-consumption is quite stable and has a fixed upper bound for a lot of cases.
-
-If you don't want to think about how much memory the library should allocate
-at all time or have a very dynamic UI with unpredictable memory consumption
-habits but still want control over memory allocation you can use the dynamic
-allocator based API. The allocator consists of two callbacks for allocating
-and freeing memory and optional userdata so you can plugin your own allocator.
-
-The final and easiest way can be used by defining
-NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory
-allocation functions malloc and free and takes over complete control over
-memory in this library.
-### Text Editor
-Editing text in this library is handled by either `nk_edit_string` or
-`nk_edit_buffer`. But like almost everything in this library there are multiple
-ways of doing it and a balance between control and ease of use with memory
-as well as functionality controlled by flags.
-This library generally allows three different levels of memory control:
-First of is the most basic way of just providing a simple char array with
-string length. This method is probably the easiest way of handling simple
-user text input. Main upside is complete control over memory while the biggest
-downside in comparison with the other two approaches is missing undo/redo.
-For UIs that require undo/redo the second way was created. It is based on
-a fixed size nk_text_edit struct, which has an internal undo/redo stack.
-This is mainly useful if you want something more like a text editor but don't want
-to have a dynamically growing buffer.
-The final way is using a dynamically growing nk_text_edit struct, which
-has both a default version if you don't care where memory comes from and an
-allocator version if you do. While the text editor is quite powerful for its
-complexity I would not recommend editing gigabytes of data with it.
-It is rather designed for uses cases which make sense for a GUI library not for
-an full blown text editor.
-### Drawing
-This library was designed to be render backend agnostic so it does
-not draw anything to screen. Instead all drawn shapes, widgets
-are made of, are buffered into memory and make up a command queue.
-Each frame therefore fills the command buffer with draw commands
-that then need to be executed by the user and his own render backend.
-After that the command buffer needs to be cleared and a new frame can be
-started. It is probably important to note that the command buffer is the main
-drawing API and the optional vertex buffer API only takes this format and
-converts it into a hardware accessible format.
-
-To use the command queue to draw your own widgets you can access the
-command buffer of each window by calling `nk_window_get_canvas` after
-previously having called `nk_begin`:
-
-```c
-    void draw_red_rectangle_widget(struct nk_context *ctx)
-    {
-        struct nk_command_buffer *canvas;
-        struct nk_input *input = &ctx->input;
-        canvas = nk_window_get_canvas(ctx);
-
-        struct nk_rect space;
-        enum nk_widget_layout_states state;
-        state = nk_widget(&space, ctx);
-        if (!state) return;
-
-        if (state != NK_WIDGET_ROM)
-            update_your_widget_by_user_input(...);
-        nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0));
-    }
-
-    if (nk_begin(...)) {
-        nk_layout_row_dynamic(ctx, 25, 1);
-        draw_red_rectangle_widget(ctx);
-    }
-    nk_end(..)
-
-```
-Important to know if you want to create your own widgets is the `nk_widget`
-call. It allocates space on the panel reserved for this widget to be used,
-but also returns the state of the widget space. If your widget is not seen and does
-not have to be updated it is '0' and you can just return. If it only has
-to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both
-update and draw your widget. The reason for separating is to only draw and
-update what is actually necessary which is crucial for performance.
-Draw List
-The optional vertex buffer draw list provides a 2D drawing context
-with antialiasing functionality which takes basic filled or outlined shapes
-or a path and outputs vertexes, elements and draw commands.
-The actual draw list API is not required to be used directly while using this
-library since converting the default library draw command output is done by
-just calling `nk_convert` but I decided to still make this library accessible
-since it can be useful.
-
-The draw list is based on a path buffering and polygon and polyline
-rendering API which allows a lot of ways to draw 2D content to screen.
-In fact it is probably more powerful than needed but allows even more crazy
-things than this library provides by default.
-### Stack
-The style modifier stack can be used to temporarily change a
-property inside `nk_style`. For example if you want a special
-red button you can temporarily push the old button color onto a stack
-draw the button with a red color and then you just pop the old color
-back from the stack:
-
-    nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0)));
-    nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0)));
-    nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0)));
-    nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2));
-
-    nk_button(...);
-
-    nk_style_pop_style_item(ctx);
-    nk_style_pop_style_item(ctx);
-    nk_style_pop_style_item(ctx);
-    nk_style_pop_vec2(ctx);
-
-Nuklear has a stack for style_items, float properties, vector properties,
-flags, colors, fonts and for button_behavior. Each has it's own fixed size stack
-which can be changed at compile time.
-### Math
- Since nuklear is supposed to work on all systems providing floating point
- math without any dependencies I also had to implement my own math functions
- for sqrt, sin and cos. Since the actual highly accurate implementations for
- the standard library functions are quite complex and I do not need high
- precision for my use cases I use approximations.
- Sqrt
- ----
- For square root nuklear uses the famous fast inverse square root:
- https://en.wikipedia.org/wiki/Fast_inverse_square_root with
- slightly tweaked magic constant. While on today's hardware it is
- probably not faster it is still fast and accurate enough for
- nuklear's use cases. IMPORTANT: this requires float format IEEE 754
- Sine/Cosine
- -----------
- All constants inside both function are generated Remez's minimax
- approximations for value range 0...2*PI. The reason why I decided to
- approximate exactly that range is that nuklear only needs sine and
- cosine to generate circles which only requires that exact range.
- In addition I used Remez instead of Taylor for additional precision:
- www.lolengine.net/blog/2011/12/21/better-function-approximations.
- The tool I used to generate constants for both sine and cosine
- (it can actually approximate a lot more functions) can be
- found here: www.lolengine.net/wiki/oss/lolremez
-        -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X"
-X...XXXXXXXXXXXXX...X -           "
-## License
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
-   ------------------------------------------------------------------------------
-   This software is available under 2 licenses -- choose whichever you prefer.
-   ------------------------------------------------------------------------------
-   ALTERNATIVE A - MIT License
-   Copyright (c) 2016-2018 Micha Mettke
-   Permission is hereby granted, free of charge, to any person obtaining a copy of
-   this software and associated documentation files (the "Software"), to deal in
-   the Software without restriction, including without limitation the rights to
-   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-   of the Software, and to permit persons to whom the Software is furnished to do
-   so, subject to the following conditions:
-   The above copyright notice and this permission notice shall be included in all
-   copies or substantial portions of the Software.
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-   SOFTWARE.
-   ------------------------------------------------------------------------------
-   ALTERNATIVE B - Public Domain (www.unlicense.org)
-   This is free and unencumbered software released into the public domain.
-   Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-   software, either in source code form or as a compiled binary, for any purpose,
-   commercial or non-commercial, and by any means.
-   In jurisdictions that recognize copyright laws, the author or authors of this
-   software dedicate any and all copyright interest in the software to the public
-   domain. We make this dedication for the benefit of the public at large and to
-   the detriment of our heirs and successors. We intend this dedication to be an
-   overt act of relinquishment in perpetuity of all present and future rights to
-   this software under copyright law.
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-   AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-   ------------------------------------------------------------------------------
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-## Changelog
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none
-[date] ([x.y.z]) - [description]
-- [date]: date on which the change has been pushed
-- [x.y.z]: Version string, represented in Semantic Versioning format
-  - [x]: Major version with API and library breaking changes
-  - [y]: Minor version with non-breaking API and library changes
-  - [z]: Patch version with no direct changes to the API
-- 2022/12/17 (4.10.5) - Fix nk_font_bake_pack() using TTC font offset incorrectly
-- 2022/10/24 (4.10.4) - Fix nk_str_{append,insert}_str_utf8 always returning 0
-- 2022/09/03 (4.10.3) - Renamed the `null` texture variable to `tex_null`
-- 2022/08/01 (4.10.2) - Fix Apple Silicon with incorrect NK_SITE_TYPE and NK_POINTER_TYPE
-- 2022/08/01 (4.10.1) - Fix cursor jumping back to beginning of text when typing more than
-                        nk_edit_xxx limit
-- 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug
-- 2022/04/18 (4.9.7)  - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to
-                        only trigger when the mouse position was inside the same button on down
-- 2022/02/03 (4.9.6)  - Allow overriding the NK_INV_SQRT function, similar to NK_SIN and NK_COS
-- 2021/12/22 (4.9.5)  - Revert layout bounds not accounting for padding due to regressions
-- 2021/12/22 (4.9.4)  - Fix checking hovering when window is minimized
-- 2021/12/22 (4.09.3) - Fix layout bounds not accounting for padding
-- 2021/12/19 (4.09.2) - Update to stb_rect_pack.h v1.01 and stb_truetype.h v1.26
-- 2021/12/16 (4.09.1) - Fix the majority of GCC warnings
-- 2021/10/16 (4.09.0) - Added nk_spacer() widget
-- 2021/09/22 (4.08.6) - Fix "may be used uninitialized" warnings in nk_widget
-- 2021/09/22 (4.08.5) - GCC __builtin_offsetof only exists in version 4 and later
-- 2021/09/15 (4.08.4) - Fix "'num_len' may be used uninitialized" in nk_do_property
-- 2021/09/15 (4.08.3) - Fix "Templates cannot be declared to have 'C' Linkage"
-- 2021/09/08 (4.08.2) - Fix warnings in C89 builds
-- 2021/09/08 (4.08.1) - Use compiler builtins for NK_OFFSETOF when possible
-- 2021/08/17 (4.08.0) - Implemented 9-slice scaling support for widget styles
-- 2021/08/16 (4.07.5) - Replace usage of memset in nk_font_atlas_bake with NK_MEMSET
-- 2021/08/15 (4.07.4) - Fix conversion and sign conversion warnings
-- 2021/08/08 (4.07.3) - Fix crash when baking merged fonts
-- 2021/08/08 (4.07.2) - Fix Multiline Edit wrong offset
-- 2021/03/17 (4.07.1) - Fix warning about unused parameter
-- 2021/03/17 (4.07.0) - Fix nk_property hover bug
-- 2021/03/15 (4.06.4) - Change nk_propertyi back to int
-- 2021/03/15 (4.06.3) - Update documentation for functions that now return nk_bool
-- 2020/12/19 (4.06.2) - Fix additional C++ style comments which are not allowed in ISO C90.
-- 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90.
-- 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool
-- 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management.
-- 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool
-- 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL
-- 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes.
-- 2020/06/04 (4.03.0) - Made nk_combo header symbols optional.
-- 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget.
-- 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug
-- 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS
-- 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug
-- 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings
-                      - Fixed compiler warnings if you bring your own methods for
-                       nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa
-- 2020/04/06 (4.01.10) - Fix bug: Do not use pool before checking for NULL
-- 2020/03/22 (4.01.9) - Fix bug where layout state wasn't restored correctly after
-                       popping a tree.
-- 2020/03/11 (4.01.8) - Fix bug where padding is subtracted from widget
-- 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice
-- 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them
-- 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT
-- 2019/10/09 (4.01.4) - Fix bug for autoscrolling in nk_do_edit
-- 2019/09/20 (4.01.3) - Fixed a bug wherein combobox cannot be closed by clicking the header
-                       when NK_BUTTON_TRIGGER_ON_RELEASE is defined.
-- 2019/09/10 (4.01.2) - Fixed the nk_cos function, which deviated significantly.
-- 2019/09/08 (4.01.1) - Fixed a bug wherein re-baking of fonts caused a segmentation
-                       fault due to dst_font->glyph_count not being zeroed on subsequent
-                       bakes of the same set of fonts.
-- 2019/06/23 (4.01.0) - Added nk_***_get_scroll and nk_***_set_scroll for groups, windows, and popups.
-- 2019/06/12 (4.00.3) - Fix panel background drawing bug.
-- 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to "fix" state based backends
-                       like GLFW without breaking key repeat behavior on event based.
-- 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame.
-- 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to
-                       clear provided buffers. So make sure to either free
-                       or clear each passed buffer after calling nk_convert.
-- 2018/02/23 (3.00.6) - Fixed slider dragging behavior.
-- 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process.
-- 2018/01/31 (3.00.4) - Removed name collision with stb_truetype.
-- 2018/01/28 (3.00.3) - Fixed panel window border drawing bug.
-- 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separated group identifier and title.
-- 2018/01/07 (3.00.1) - Started to change documentation style.
-- 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken
-                       because of conversions between float and byte color representation.
-                       Color pickers now use floating point values to represent
-                       HSV values. To get back the old behavior I added some additional
-                       color conversion functions to cast between nk_color and
-                       nk_colorf.
-- 2017/12/23 (2.00.7) - Fixed small warning.
-- 2017/12/23 (2.00.7) - Fixed `nk_edit_buffer` behavior if activated to allow input.
-- 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior.
-- 2017/12/04 (2.00.6) - Added formatted string tooltip widget.
-- 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag `NK_WINDOW_NO_INPUT`.
-- 2017/11/15 (2.00.4) - Fixed font merging.
-- 2017/11/07 (2.00.3) - Fixed window size and position modifier functions.
-- 2017/09/14 (2.00.2) - Fixed `nk_edit_buffer` and `nk_edit_focus` behavior.
-- 2017/09/14 (2.00.1) - Fixed window closing behavior.
-- 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifying window position and size functions now
-                       require the name of the window and must happen outside the window
-                       building process (between function call nk_begin and nk_end).
-- 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last.
-- 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows.
-- 2017/08/27 (1.40.7) - Fixed window background flag.
-- 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked
-                       query for widgets.
-- 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked
-                       and filled rectangles.
-- 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in
-                       process of being destroyed.
-- 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in
-                       window instead of directly in table.
-- 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro.
-- 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero.
-- 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only
-                       comes in effect if you pass in zero was row height argument.
-- 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change
-                       how layouting works. From now there will be an internal minimum
-                       row height derived from font height. If you need a row smaller than
-                       that you can directly set it by `nk_layout_set_min_row_height` and
-                       reset the value back by calling `nk_layout_reset_min_row_height.
-- 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix.
-- 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a `nk_layout_xxx` function.
-- 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer.
-- 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped.
-- 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundaries.
-- 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space.
-- 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size.
-- 2017/05/06 (1.38.0) - Added platform double-click support.
-- 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends.
-- 2017/04/20 (1.37.0) - Extended properties with selection and clipboard support.
-- 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing.
-- 2017/04/09 (1.36.1) - Fixed #403 with another widget float error.
-- 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags.
-- 2017/04/09 (1.35.3) - Fixed buffer heap corruption.
-- 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows.
-- 2017/03/25 (1.35.1) - Fixed windows closing behavior.
-- 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377.
-- 2017/03/18 (1.34.3) - Fixed long window header titles.
-- 2017/03/04 (1.34.2) - Fixed text edit filtering.
-- 2017/03/04 (1.34.1) - Fixed group closable flag.
-- 2017/02/25 (1.34.0) - Added custom draw command for better language binding support.
-- 2017/01/24 (1.33.0) - Added programmatic way to remove edit focus.
-- 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows.
-- 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows.
-- 2017/01/21 (1.32.1) - Fixed slider behavior and drawing.
-- 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner.
-- 2017/01/13 (1.31.0) - Added additional row layouting method to combine both
-                       dynamic and static widgets.
-- 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit.
-- 2016/12/31 (1.29.2) - Fixed closing window bug of minimized windows.
-- 2016/12/03 (1.29.1) - Fixed wrapped text with no separator and C89 error.
-- 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters.
-- 2016/11/22 (1.28.6) - Fixed window minimized closing bug.
-- 2016/11/19 (1.28.5) - Fixed abstract combo box closing behavior.
-- 2016/11/19 (1.28.4) - Fixed tooltip flickering.
-- 2016/11/19 (1.28.3) - Fixed memory leak caused by popup repeated closing.
-- 2016/11/18 (1.28.2) - Fixed memory leak caused by popup panel allocation.
-- 2016/11/10 (1.28.1) - Fixed some warnings and C++ error.
-- 2016/11/10 (1.28.0) - Added additional `nk_button` versions which allows to directly
-                       pass in a style struct to change buttons visual.
-- 2016/11/10 (1.27.0) - Added additional `nk_tree` versions to support external state
-                       storage. Just like last the `nk_group` commit the main
-                       advantage is that you optionally can minimize nuklears runtime
-                       memory consumption or handle hash collisions.
-- 2016/11/09 (1.26.0) - Added additional `nk_group` version to support external scrollbar
-                       offset storage. Main advantage is that you can externalize
-                       the memory management for the offset. It could also be helpful
-                       if you have a hash collision in `nk_group_begin` but really
-                       want the name. In addition I added `nk_list_view` which allows
-                       to draw big lists inside a group without actually having to
-                       commit the whole list to nuklear (issue #269).
-- 2016/10/30 (1.25.1) - Fixed clipping rectangle bug inside `nk_draw_list`.
-- 2016/10/29 (1.25.0) - Pulled `nk_panel` memory management into nuklear and out of
-                       the hands of the user. From now on users don't have to care
-                       about panels unless they care about some information. If you
-                       still need the panel just call `nk_window_get_panel`.
-- 2016/10/21 (1.24.0) - Changed widget border drawing to stroked rectangle from filled
-                       rectangle for less overdraw and widget background transparency.
-- 2016/10/18 (1.23.0) - Added `nk_edit_focus` for manually edit widget focus control.
-- 2016/09/29 (1.22.7) - Fixed deduction of basic type in non `<stdint.h>` compilation.
-- 2016/09/29 (1.22.6) - Fixed edit widget UTF-8 text cursor drawing bug.
-- 2016/09/28 (1.22.5) - Fixed edit widget UTF-8 text appending/inserting/removing.
-- 2016/09/28 (1.22.4) - Fixed drawing bug inside edit widgets which offset all text
-                       text in every edit widget if one of them is scrolled.
-- 2016/09/28 (1.22.3) - Fixed small bug in edit widgets if not active. The wrong
-                       text length is passed. It should have been in bytes but
-                       was passed as glyphs.
-- 2016/09/20 (1.22.2) - Fixed color button size calculation.
-- 2016/09/20 (1.22.1) - Fixed some `nk_vsnprintf` behavior bugs and removed `<stdio.h>`
-                       again from `NK_INCLUDE_STANDARD_VARARGS`.
-- 2016/09/18 (1.22.0) - C89 does not support vsnprintf only C99 and newer as well
-                       as C++11 and newer. In addition to use vsnprintf you have
-                       to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`
-                       is not enough. That behavior is now fixed. By default if
-                       both varargs as well as stdio is selected I try to use
-                       vsnprintf if not possible I will revert to vsprintf. If
-                       varargs but not stdio was defined I will use my own function.
-- 2016/09/15 (1.21.2) - Fixed panel `close` behavior for deeper panel levels.
-- 2016/09/15 (1.21.1) - Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`.
-- 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,
-                       and contextual which prevented closing in y-direction if
-                       popup did not reach max height.
-                       In addition the height parameter was changed into vec2
-                       for width and height to have more control over the popup size.
-- 2016/09/13 (1.20.3) - Cleaned up and extended type selection.
-- 2016/09/13 (1.20.2) - Fixed slider behavior hopefully for the last time. This time
-                       all calculation are correct so no more hackery.
-- 2016/09/13 (1.20.1) - Internal change to divide window/panel flags into panel flags and types.
-                       Suprisinly spend years in C and still happened to confuse types
-                       with flags. Probably something to take note.
-- 2016/09/08 (1.20.0) - Added additional helper function to make it easier to just
-                       take the produced buffers from `nk_convert` and unplug the
-                       iteration process from `nk_context`. So now you can
-                       just use the vertex,element and command buffer + two pointer
-                       inside the command buffer retrieved by calls `nk__draw_begin`
-                       and `nk__draw_end` and macro `nk_draw_foreach_bounded`.
-- 2016/09/08 (1.19.0) - Added additional asserts to make sure every `nk_xxx_begin` call
-                       for windows, popups, combobox, menu and contextual is guarded by
-                       `if` condition and does not produce false drawing output.
-- 2016/09/08 (1.18.0) - Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`
-                       to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and
-                       `NK_SYMBOL_RECT_OUTLINE`.
-- 2016/09/08 (1.17.0) - Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`
-                       to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and
-                       `NK_SYMBOL_CIRCLE_OUTLINE`.
-- 2016/09/08 (1.16.0) - Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`
-                       is not defined by supporting the biggest compiler GCC, clang and MSVC.
-- 2016/09/07 (1.15.3) - Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error.
-- 2016/09/04 (1.15.2) - Fixed wrong combobox height calculation.
-- 2016/09/03 (1.15.1) - Fixed gaps inside combo boxes in OpenGL.
-- 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and
-                       instead made it user provided. The range of types to convert
-                       to is quite limited at the moment, but I would be more than
-                       happy to accept PRs to add additional.
-- 2016/08/30 (1.14.2) - Removed unused variables.
-- 2016/08/30 (1.14.1) - Fixed C++ build errors.
-- 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly.
-- 2016/08/30 (1.13.4) - Tweaked some default styling variables.
-- 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would
-                       refrain from using slider with a big number of steps.
-- 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the
-                       window was in Read Only Mode.
-- 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just
-                       a hack for combo box and menu.
-- 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since
-                       it is bugged and causes issues in window selection.
-- 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now
-                       determined by the scrollbar size.
-- 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11.0.
-- 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection.
-- 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code
-                       handling panel padding and panel border.
-- 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx`.
-- 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups.
-- 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes.
-- 2016/08/26 (1.10.0) - Added window name string prepresentation to account for
-                       hash collisions. Currently limited to `NK_WINDOW_MAX_NAME`
-                       which in term can be redefined if not big enough.
-- 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code.
-- 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'
-                       to account for key press and release happening in one frame.
-- 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate.
-- 2016/08/17 (1.09.6) - Removed invalid check for value zero in `nk_propertyx`.
-- 2016/08/16 (1.09.5) - Fixed ROM mode for deeper levels of popup windows parents.
-- 2016/08/15 (1.09.4) - Editbox are now still active if enter was pressed with flag
-                       `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep
-                       typing after committing.
-- 2016/08/15 (1.09.4) - Removed redundant code.
-- 2016/08/15 (1.09.4) - Fixed negative numbers in `nk_strtoi` and remove unused variable.
-- 2016/08/15 (1.09.3) - Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background
-                       window only as selected by hovering and not by clicking.
-- 2016/08/14 (1.09.2) - Fixed a bug in font atlas which caused wrong loading
-                       of glyphs for font with multiple ranges.
-- 2016/08/12 (1.09.1) - Added additional function to check if window is currently
-                       hidden and therefore not visible.
-- 2016/08/12 (1.09.1) - nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`
-                       instead of the old flag `NK_WINDOW_HIDDEN`.
-- 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed
-                       the underlying implementation to not cast to float and instead
-                       work directly on the given values.
-- 2016/08/09 (1.08.0) - Added additional define to overwrite library internal
-                       floating pointer number to string conversion for additional
-                       precision.
-- 2016/08/09 (1.08.0) - Added additional define to overwrite library internal
-                       string to floating point number conversion for additional
-                       precision.
-- 2016/08/08 (1.07.2) - Fixed compiling error without define `NK_INCLUDE_FIXED_TYPE`.
-- 2016/08/08 (1.07.1) - Fixed possible floating point error inside `nk_widget` leading
-                       to wrong widget width calculation which results in widgets falsely
-                       becoming tagged as not inside window and cannot be accessed.
-- 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and
-                       closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown
-                       by using `nk_window_show` and closed by either clicking the close
-                       icon in a window or by calling `nk_window_close`. Only closed
-                       windows get removed at the end of the frame while hidden windows
-                       remain.
-- 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to
-                       `nk_edit_string` which takes, edits and outputs a '\0' terminated string.
-- 2016/08/08 (1.05.4) - Fixed scrollbar auto hiding behavior.
-- 2016/08/08 (1.05.3) - Fixed wrong panel padding selection in `nk_layout_widget_space`.
-- 2016/08/07 (1.05.2) - Fixed old bug in dynamic immediate mode layout API, calculating
-                       wrong item spacing and panel width.
-- 2016/08/07 (1.05.1) - Hopefully finally fixed combobox popup drawing bug.
-- 2016/08/07 (1.05.0) - Split varargs away from `NK_INCLUDE_STANDARD_IO` into own
-                       define `NK_INCLUDE_STANDARD_VARARGS` to allow more fine
-                       grained controlled over library includes.
-- 2016/08/06 (1.04.5) - Changed memset calls to `NK_MEMSET`.
-- 2016/08/04 (1.04.4) - Fixed fast window scaling behavior.
-- 2016/08/04 (1.04.3) - Fixed window scaling, movement bug which appears if you
-                       move/scale a window and another window is behind it.
-                       If you are fast enough then the window behind gets activated
-                       and the operation is blocked. I now require activating
-                       by hovering only if mouse is not pressed.
-- 2016/08/04 (1.04.2) - Fixed changing fonts.
-- 2016/08/03 (1.04.1) - Fixed `NK_WINDOW_BACKGROUND` behavior.
-- 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image`.
-- 2016/08/03 (1.04.0) - Added additional window padding style attributes for
-                       sub windows (combo, menu, ...).
-- 2016/08/03 (1.04.0) - Added functions to show/hide software cursor.
-- 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window
-                       to be always in the background of the screen.
-- 2016/08/03 (1.03.2) - Removed invalid assert macro for NK_RGB color picker.
-- 2016/08/01 (1.03.1) - Added helper macros into header include guard.
-- 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to
-                       simplify memory management by removing the need to
-                       allocate the pool.
-- 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled
-                       will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT
-                       seconds without window interaction. To make it work
-                       you have to also set a delta time inside the `nk_context`.
-- 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs.
-- 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context`.
-- 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument.
-- 2016/07/15 (1.01.0) - Removed internal font baking API and simplified
-                       font atlas memory management by converting pointer
-                       arrays for fonts and font configurations to lists.
-- 2016/07/15 (1.00.0) - Changed button API to use context dependent button
-                       behavior instead of passing it for every function call.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-## Gallery
-![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)
-![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)
-![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png)
-![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png)
-![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png)
-![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png)
-![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)
-![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)
-![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)
-## Credits
-Developed by Micha Mettke and every direct or indirect github contributor. <br /><br />
-Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain) <br />
-Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from [email protected] for documentation generation <br /><br />
-Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). <br />
-Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and
-giving me the inspiration for this library, Casey Muratori for handmade hero
-and his original immediate mode graphical user interface idea and Sean
-Barret for his amazing single header libraries which restored my faith
-in libraries and brought me to create some of my own. Finally Apoorva Joshi
-for his single header file packer.
-<script>markdeepOptions={tocStyle:'medium'};</script>
-<!-- Markdeep: --><script src='https://casual-effects.com/markdeep/latest/markdeep.min.js?'></script>

+ 0 - 11
doc/nuklear.html

@@ -1,11 +0,0 @@
-<!--
-    This page is here in order to allow redirecting the old nuklear.html URL over to index.html
--->
-<html>
-    <head>
-        <meta http-equiv="refresh" content="0; URL=index.html" />
-    </head>
-    <body>
-        <p>If you are not redirected in five seconds, <a href="index.html">click here</a>.</p>
-    </body>
-</html>

+ 0 - 141
doc/stddoc.c

@@ -1,141 +0,0 @@
-/// ## About
-/// - _stddoc.c_ is a tiny documentation generator for 60 programming languages.
-/// - This page sample was auto-generated from the code comments found in `stddoc.c` file.
-///
-/// ## How does it work?
-/// - Markdeep code comments are extracted from stdin and printed into stdout as a HTML file.
-///
-/// ## Supported languages
-/// - `/// Three slashes comment` [ActionScript, AngelScript, C (C99), C#, C++, ChaiScript, D,
-///   GameMonkey, GML, Go, Java, JavaScript, JetScript, jtc, Jx9, Kotlin, Neko, Object Pascal (Delphi),
-///   Objective-C, Pawn, PHP, QuakeC, Rust, SASS, Scala, Squirrel, Swift, Vala, Wren, Xojo].
-/// - `--- Three dashes comment` [Ada, AppleScript, Eiffel, Euphoria, Haskell, Lua, Occam,
-///   PL/SQL, PSL, SGML, SPARK, SQL, Terra, TSQL, VHDL].
-/// - `### Three hashes comment` [AWK, Bash, Bourne shell, C shell, Cobra, Maple, Maple,
-///   Perl, Perl6, PowerShell, Python, R, Ruby, Seed7, Tcl]. 
-///
-/// ## Usage
-/// - `stddoc < source.code > documentation.html`
-///
-/// ## Changelog
-/// 2018/01/07
-/// :  Initial version (_v1.0.0_)
-///
-/// ## License
-/// - rlyeh, unlicensed (~public domain).
-
-#include <stdio.h>
-
-int main() {
-    printf("%s\n", "<meta charset='utf-8' emacsmode='-*- markdown -*-'>");
-    printf("%s\n", "<link rel='stylesheet' href='https://casual-effects.com/markdeep/latest/apidoc.css?'>");
-
-    for( int fsm_S = 0, fsm_D = 0, fsm_H = 0; !feof(stdin); ) {
-        int chr = getc(stdin);
-        if( fsm_S > 3 || fsm_D > 3 || fsm_H > 3 ) {
-            putc(chr, stdout);
-            if( chr != '\r' && chr != '\n' ) continue;
-        }
-        /**/ if( fsm_S <= 2 && chr == '/' && !fsm_D && !fsm_H ) fsm_S++;
-        else if( fsm_S == 3 && chr == ' ' && !fsm_D && !fsm_H ) fsm_S++;
-        else if( fsm_D <= 2 && chr == '-' && !fsm_S && !fsm_H ) fsm_D++;
-        else if( fsm_D == 3 && chr == ' ' && !fsm_S && !fsm_H ) fsm_D++;
-        else if( fsm_H <= 2 && chr == '#' && !fsm_S && !fsm_D ) fsm_H++;
-        else if( fsm_H == 3 && chr == ' ' && !fsm_S && !fsm_D ) fsm_H++;
-        else fsm_S = fsm_D = fsm_H = 0;
-    }
-
-    printf("%s\n", "<script>markdeepOptions={tocStyle:'medium'};</script>");
-    printf("%s\n", "<!-- Markdeep: --><script src='https://casual-effects.com/markdeep/latest/markdeep.min.js?'></script>");
-}
-
-///
-/// ## **Example page!**
-/// 
-/// Imaginary documentation page. Here would be some introduction text.
-/// 
-/// The table of contents that Markdeep produces is stuffed on the right side, 
-/// if the browser window is wide enough. Otherwise it is hidden.
-/// 
-/// ### Basic Markdeep
-/// 
-/// Regular styling like **bold**, _italics_, ~~strikethrough~~, `inline code`, etc. Lists as:
-/// 
-/// * A
-/// * Bullet
-/// * List
-/// 
-/// And:
-/// 
-/// 1. A
-/// 1. Numbered
-/// 1. List!
-/// 
-/// Symbol substitutions: a 45-degree turn; some x -> y arrows; some whoa ==> fancy <==> arrows.
-/// 
-/// Is this a definition list?
-/// :   Looks like one to me
-/// Is that right?
-/// :   Possibly!
-/// 
-/// And a code listing:
-/// 
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-/// int main()
-/// {
-///     return 1;
-/// }
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-/// 
-/// 
-/// ### Tables
-/// 
-/// Thing Name              | Description        |Notes
-/// ------------------------|--------------------|-----
-/// Yes                     | Yup!               |
-/// No                      | Nope :(            |
-/// FileNotFound            | Doesn't find files | Pass `-sFIND_FILE=maybe` to maybe find them
-/// 
-/// 
-/// ### Diagrams
-/// 
-/// *******************************************  Here's a text to the right of the diagram,
-/// * +-----------------+           .-.       *  ain't that fancy. Pretty fancy indeed, I
-/// * |\                |        .-+   |      *  must say! Markdeep diagrams are generally
-/// * | \     A-B   *---+--> .--+       '--.  *  enclosed into a rectangle full made of `*`
-/// * |  \              |   |     Cloud!    | *  symbols; and are "drawn" using ASCII-art
-/// * +---+-------------+    '-------------'  *  style, with `- | + / \ * o` etc.
-/// *******************************************  Suh-weet!
-/// 
-/// Another random diagram, just because:
-/// 
-/// ********************
-/// *    +-+-+-+-*-o   *
-/// *   / / ^ /        *
-/// *  / v / /         *
-/// * +-+-+-+          *
-/// ********************
-/// 
-/// ### Special notes
-/// 
-/// !!! Note
-///     Hey I'm a note. Don't mind me, I'm just sitting here.
-/// 
-/// !!! WARNING
-///     I'm a warning, perhaps. *Something might happen!*
-/// 
-/// !!! Error: Never Pass `nullptr` to a Shader
-///     Invoking a shader with a null argument can seg fault.
-///     This is a multi-line admonition.
-/// 
-///     Seriously, don't call shaders like that.
-/// 
-/// ### Embedding HTML
-/// 
-/// <pre>
-/// This is an embedded html node by the way!
-/// </pre>
-/// 
-/// ## Credits
-/// - API doc style created by [Aras Pranckevičius](https://github.com/aras-p)
-/// - Markdeep by [Morgan McGuire](https://casual-effects.com/markdeep/).

File diff suppressed because it is too large
+ 1100 - 1068
nuklear.h


+ 0 - 216
src/HEADER

@@ -1,216 +0,0 @@
-/// # Nuklear
-/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
-///
-/// ## Contents
-/// 1. About section
-/// 2. Highlights section
-/// 3. Features section
-/// 4. Usage section
-///     1. Flags section
-///     2. Constants section
-///     3. Dependencies section
-/// 5. Example section
-/// 6. API section
-///     1. Context section
-///     2. Input section
-///     3. Drawing section
-///     4. Window section
-///     5. Layouting section
-///     6. Groups section
-///     7. Tree section
-///     8. Properties section
-/// 7. License section
-/// 8. Changelog section
-/// 9. Gallery section
-/// 10. Credits section
-///
-/// ## About
-/// This is a minimal state immediate mode graphical user interface toolkit
-/// written in ANSI C and licensed under public domain. It was designed as a simple
-/// embeddable user interface for application and does not have any dependencies,
-/// a default renderbackend or OS window and input handling but instead provides a very modular
-/// library approach by using simple input state for input and draw
-/// commands describing primitive shapes as output. So instead of providing a
-/// layered library that tries to abstract over a number of platform and
-/// render backends it only focuses on the actual UI.
-///
-/// ## Highlights
-/// - Graphical user interface toolkit
-/// - Single header library
-/// - Written in C89 (a.k.a. ANSI C or ISO C90)
-/// - Small codebase (~18kLOC)
-/// - Focus on portability, efficiency and simplicity
-/// - No dependencies (not even the standard library if not wanted)
-/// - Fully skinnable and customizable
-/// - Low memory footprint with total memory control if needed or wanted
-/// - UTF-8 support
-/// - No global or hidden state
-/// - Customizable library modules (you can compile and use only what you need)
-/// - Optional font baker and vertex buffer output
-/// - [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)
-///
-/// ## Features
-/// - Absolutely no platform dependent code
-/// - Memory management control ranging from/to
-///     - Ease of use by allocating everything from standard library
-///     - Control every byte of memory inside the library
-/// - Font handling control ranging from/to
-///     - Use your own font implementation for everything
-///     - Use this libraries internal font baking and handling API
-/// - Drawing output control ranging from/to
-///     - Simple shapes for more high level APIs which already have drawing capabilities
-///     - Hardware accessible anti-aliased vertex buffer output
-/// - Customizable colors and properties ranging from/to
-///     - Simple changes to color by filling a simple color table
-///     - Complete control with ability to use skinning to decorate widgets
-/// - Bendable UI library with widget ranging from/to
-///     - Basic widgets like buttons, checkboxes, slider, ...
-///     - Advanced widget like abstract comboboxes, contextual menus,...
-/// - Compile time configuration to only compile what you need
-///     - Subset which can be used if you do not want to link or use the standard library
-/// - Can be easily modified to only update on user input instead of frame updates
-///
-/// ## Usage
-/// This library is self contained in one single header file and can be used either
-/// in header only mode or in implementation mode. The header only mode is used
-/// by default when included and allows including this header in other headers
-/// and does not contain the actual implementation. <br /><br />
-///
-/// The implementation mode requires to define  the preprocessor macro
-/// NK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:
-///
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C
-///     #define NK_IMPLEMENTATION
-///     #include "nuklear.h"
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-///
-/// Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
-/// below in header and implementation mode if you want to use additional functionality
-/// or need more control over the library.
-///
-/// !!! WARNING
-///     Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.
-///
-/// ### Flags
-/// Flag                            | Description
-/// --------------------------------|------------------------------------------
-/// NK_PRIVATE                      | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation
-/// NK_INCLUDE_FIXED_TYPES          | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
-/// NK_INCLUDE_DEFAULT_ALLOCATOR    | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
-/// NK_INCLUDE_STANDARD_IO          | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
-/// NK_INCLUDE_STANDARD_VARARGS     | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
-/// NK_INCLUDE_STANDARD_BOOL        | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
-/// NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
-/// NK_INCLUDE_FONT_BAKING          | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
-/// NK_INCLUDE_DEFAULT_FONT         | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
-/// NK_INCLUDE_COMMAND_USERDATA     | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.
-/// NK_BUTTON_TRIGGER_ON_RELEASE    | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.
-/// NK_ZERO_COMMAND_MEMORY          | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.
-/// NK_UINT_DRAW_INDEX              | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit
-/// NK_KEYSTATE_BASED_INPUT         | Define this if your backend uses key state for each frame rather than key press/release events
-///
-/// !!! WARNING
-///     The following flags will pull in the standard C library:
-///     - NK_INCLUDE_DEFAULT_ALLOCATOR
-///     - NK_INCLUDE_STANDARD_IO
-///     - NK_INCLUDE_STANDARD_VARARGS
-///
-/// !!! WARNING
-///     The following flags if defined need to be defined for both header and implementation:
-///     - NK_INCLUDE_FIXED_TYPES
-///     - NK_INCLUDE_DEFAULT_ALLOCATOR
-///     - NK_INCLUDE_STANDARD_VARARGS
-///     - NK_INCLUDE_STANDARD_BOOL
-///     - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
-///     - NK_INCLUDE_FONT_BAKING
-///     - NK_INCLUDE_DEFAULT_FONT
-///     - NK_INCLUDE_STANDARD_VARARGS
-///     - NK_INCLUDE_COMMAND_USERDATA
-///     - NK_UINT_DRAW_INDEX
-///
-/// ### Constants
-/// Define                          | Description
-/// --------------------------------|---------------------------------------
-/// NK_BUFFER_DEFAULT_INITIAL_SIZE  | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.
-/// NK_MAX_NUMBER_BUFFER            | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.
-/// NK_INPUT_MAX                    | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.
-///
-/// !!! WARNING
-///     The following constants if defined need to be defined for both header and implementation:
-///     - NK_MAX_NUMBER_BUFFER
-///     - NK_BUFFER_DEFAULT_INITIAL_SIZE
-///     - NK_INPUT_MAX
-///
-/// ### Dependencies
-/// Function    | Description
-/// ------------|---------------------------------------------------------------
-/// NK_ASSERT   | If you don't define this, nuklear will use <assert.h> with assert().
-/// NK_MEMSET   | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
-/// NK_MEMCPY   | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
-/// NK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
-/// NK_SIN      | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
-/// NK_COS      | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
-/// NK_STRTOD   | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
-/// NK_DTOA     | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
-/// NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
-///
-/// !!! WARNING
-///     The following dependencies will pull in the standard C library if not redefined:
-///     - NK_ASSERT
-///
-/// !!! WARNING
-///     The following dependencies if defined need to be defined for both header and implementation:
-///     - NK_ASSERT
-///
-/// !!! WARNING
-///     The following dependencies if defined need to be defined only for the implementation part:
-///     - NK_MEMSET
-///     - NK_MEMCPY
-///     - NK_SQRT
-///     - NK_SIN
-///     - NK_COS
-///     - NK_STRTOD
-///     - NK_DTOA
-///     - NK_VSNPRINTF
-///
-/// ## Example
-///
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
-/// // init gui state
-/// enum {EASY, HARD};
-/// static int op = EASY;
-/// static float value = 0.6f;
-/// static int i =  20;
-/// struct nk_context ctx;
-///
-/// nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
-/// if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
-///     NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
-///     // fixed widget pixel width
-///     nk_layout_row_static(&ctx, 30, 80, 1);
-///     if (nk_button_label(&ctx, "button")) {
-///         // event handling
-///     }
-///
-///     // fixed widget window ratio width
-///     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;
-///
-///     // custom widget pixel width
-///     nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
-///     {
-///         nk_layout_row_push(&ctx, 50);
-///         nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
-///         nk_layout_row_push(&ctx, 110);
-///         nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
-///     }
-///     nk_layout_row_end(&ctx);
-/// }
-/// nk_end(&ctx);
-/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-///
-/// ![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
-///
-/// ## API
-///

+ 216 - 0
src/HEADER.md

@@ -0,0 +1,216 @@
+# Nuklear
+![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
+
+## Contents
+1. About section
+2. Highlights section
+3. Features section
+4. Usage section
+    1. Flags section
+    2. Constants section
+    3. Dependencies section
+5. Example section
+6. API section
+    1. Context section
+    2. Input section
+    3. Drawing section
+    4. Window section
+    5. Layouting section
+    6. Groups section
+    7. Tree section
+    8. Properties section
+7. License section
+8. Changelog section
+9. Gallery section
+10. Credits section
+
+## About
+This is a minimal state immediate mode graphical user interface toolkit
+written in ANSI C and licensed under public domain. It was designed as a simple
+embeddable user interface for application and does not have any dependencies,
+a default renderbackend or OS window and input handling but instead provides a very modular
+library approach by using simple input state for input and draw
+commands describing primitive shapes as output. So instead of providing a
+layered library that tries to abstract over a number of platform and
+render backends it only focuses on the actual UI.
+
+## Highlights
+- Graphical user interface toolkit
+- Single header library
+- Written in C89 (a.k.a. ANSI C or ISO C90)
+- Small codebase (~18kLOC)
+- Focus on portability, efficiency and simplicity
+- No dependencies (not even the standard library if not wanted)
+- Fully skinnable and customizable
+- Low memory footprint with total memory control if needed or wanted
+- UTF-8 support
+- No global or hidden state
+- Customizable library modules (you can compile and use only what you need)
+- Optional font baker and vertex buffer output
+- [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)
+
+## Features
+- Absolutely no platform dependent code
+- Memory management control ranging from/to
+    - Ease of use by allocating everything from standard library
+    - Control every byte of memory inside the library
+- Font handling control ranging from/to
+    - Use your own font implementation for everything
+    - Use this libraries internal font baking and handling API
+- Drawing output control ranging from/to
+    - Simple shapes for more high level APIs which already have drawing capabilities
+    - Hardware accessible anti-aliased vertex buffer output
+- Customizable colors and properties ranging from/to
+    - Simple changes to color by filling a simple color table
+    - Complete control with ability to use skinning to decorate widgets
+- Bendable UI library with widget ranging from/to
+    - Basic widgets like buttons, checkboxes, slider, ...
+    - Advanced widget like abstract comboboxes, contextual menus,...
+- Compile time configuration to only compile what you need
+    - Subset which can be used if you do not want to link or use the standard library
+- Can be easily modified to only update on user input instead of frame updates
+
+## Usage
+This library is self contained in one single header file and can be used either
+in header only mode or in implementation mode. The header only mode is used
+by default when included and allows including this header in other headers
+and does not contain the actual implementation. <br /><br />
+
+The implementation mode requires to define  the preprocessor macro
+NK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C
+    #define NK_IMPLEMENTATION
+    #include "nuklear.h"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Also optionally define the symbols listed in the section "OPTIONAL DEFINES"
+below in header and implementation mode if you want to use additional functionality
+or need more control over the library.
+
+!!! WARNING
+    Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.
+
+### Flags
+Flag                            | Description
+--------------------------------|------------------------------------------
+NK_PRIVATE                      | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation
+NK_INCLUDE_FIXED_TYPES          | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.
+NK_INCLUDE_DEFAULT_ALLOCATOR    | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.
+NK_INCLUDE_STANDARD_IO          | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.
+NK_INCLUDE_STANDARD_VARARGS     | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.
+NK_INCLUDE_STANDARD_BOOL        | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.
+NK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...
+NK_INCLUDE_FONT_BAKING          | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.
+NK_INCLUDE_DEFAULT_FONT         | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font
+NK_INCLUDE_COMMAND_USERDATA     | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.
+NK_BUTTON_TRIGGER_ON_RELEASE    | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.
+NK_ZERO_COMMAND_MEMORY          | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.
+NK_UINT_DRAW_INDEX              | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit
+NK_KEYSTATE_BASED_INPUT         | Define this if your backend uses key state for each frame rather than key press/release events
+
+!!! WARNING
+    The following flags will pull in the standard C library:
+    - NK_INCLUDE_DEFAULT_ALLOCATOR
+    - NK_INCLUDE_STANDARD_IO
+    - NK_INCLUDE_STANDARD_VARARGS
+
+!!! WARNING
+    The following flags if defined need to be defined for both header and implementation:
+    - NK_INCLUDE_FIXED_TYPES
+    - NK_INCLUDE_DEFAULT_ALLOCATOR
+    - NK_INCLUDE_STANDARD_VARARGS
+    - NK_INCLUDE_STANDARD_BOOL
+    - NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+    - NK_INCLUDE_FONT_BAKING
+    - NK_INCLUDE_DEFAULT_FONT
+    - NK_INCLUDE_STANDARD_VARARGS
+    - NK_INCLUDE_COMMAND_USERDATA
+    - NK_UINT_DRAW_INDEX
+
+### Constants
+Define                          | Description
+--------------------------------|---------------------------------------
+NK_BUFFER_DEFAULT_INITIAL_SIZE  | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.
+NK_MAX_NUMBER_BUFFER            | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.
+NK_INPUT_MAX                    | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.
+
+!!! WARNING
+    The following constants if defined need to be defined for both header and implementation:
+    - NK_MAX_NUMBER_BUFFER
+    - NK_BUFFER_DEFAULT_INITIAL_SIZE
+    - NK_INPUT_MAX
+
+### Dependencies
+Function    | Description
+------------|---------------------------------------------------------------
+NK_ASSERT   | If you don't define this, nuklear will use <assert.h> with assert().
+NK_MEMSET   | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.
+NK_MEMCPY   | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.
+NK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.
+NK_SIN      | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.
+NK_COS      | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.
+NK_STRTOD   | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
+NK_DTOA     | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).
+NK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.
+
+!!! WARNING
+    The following dependencies will pull in the standard C library if not redefined:
+    - NK_ASSERT
+
+!!! WARNING
+    The following dependencies if defined need to be defined for both header and implementation:
+    - NK_ASSERT
+
+!!! WARNING
+    The following dependencies if defined need to be defined only for the implementation part:
+    - NK_MEMSET
+    - NK_MEMCPY
+    - NK_SQRT
+    - NK_SIN
+    - NK_COS
+    - NK_STRTOD
+    - NK_DTOA
+    - NK_VSNPRINTF
+
+## Example
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c
+// init gui state
+enum {EASY, HARD};
+static int op = EASY;
+static float value = 0.6f;
+static int i =  20;
+struct nk_context ctx;
+
+nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
+if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
+    NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
+    // fixed widget pixel width
+    nk_layout_row_static(&ctx, 30, 80, 1);
+    if (nk_button_label(&ctx, "button")) {
+        // event handling
+    }
+
+    // fixed widget window ratio width
+    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;
+
+    // custom widget pixel width
+    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
+    {
+        nk_layout_row_push(&ctx, 50);
+        nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
+        nk_layout_row_push(&ctx, 110);
+        nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
+    }
+    nk_layout_row_end(&ctx);
+}
+nk_end(&ctx);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
+
+## API
+

+ 3 - 1
src/build.py

@@ -9,6 +9,7 @@ def print_help():
 """usage: python single_header_packer.py --macro <macro> [--intro <files>] --extern <files> --pub <files> --priv1 <files> --priv2 <files> [--outro <files>]
 
        where <files> can be a comma-separated list of files. e.g. --priv *.c,inc/*.h
+       or a space separated list encapsulated in quotes. e.g. --priv1 "file.c file2.c file3.c"
 
        The 'extern' files are placed between 'priv1' and 'priv2'.
 
@@ -33,7 +34,8 @@ def print_help():
 
 def parse_files(arg):
     files = []
-    paths = arg.split(",")
+    paths = re.split(r'[,\s]', arg)
+
     for path in paths:
         if "*" in path:
             # Wildcard

File diff suppressed because it is too large
+ 582 - 560
src/nuklear.h


+ 2 - 3
src/nuklear_buffer.c

@@ -242,7 +242,7 @@ nk_buffer_free(struct nk_buffer *b)
     b->pool.free(b->pool.userdata, b->memory.ptr);
 }
 NK_API void
-nk_buffer_info(struct nk_memory_status *s, struct nk_buffer *b)
+nk_buffer_info(struct nk_memory_status *s, const struct nk_buffer *b)
 {
     NK_ASSERT(b);
     NK_ASSERT(s);
@@ -268,10 +268,9 @@ nk_buffer_memory_const(const struct nk_buffer *buffer)
     return buffer->memory.ptr;
 }
 NK_API nk_size
-nk_buffer_total(struct nk_buffer *buffer)
+nk_buffer_total(const struct nk_buffer *buffer)
 {
     NK_ASSERT(buffer);
     if (!buffer) return 0;
     return buffer->memory.size;
 }
-

+ 2 - 3
src/nuklear_color.c

@@ -23,7 +23,7 @@ nk_parse_hex(const char *p, int length)
     return i;
 }
 NK_API struct nk_color
-nk_rgb_factor(struct nk_color col, const float factor)
+nk_rgb_factor(struct nk_color col, float factor)
 {
     if (factor == 1.0f)
         return col;
@@ -246,7 +246,7 @@ nk_hsva_colorf(float h, float s, float v, float a)
     return out;
 }
 NK_API struct nk_colorf
-nk_hsva_colorfv(float *c)
+nk_hsva_colorfv(const float *c)
 {
     return nk_hsva_colorf(c[0], c[1], c[2], c[3]);
 }
@@ -421,4 +421,3 @@ nk_color_hsv_bv(nk_byte *out, struct nk_color in)
     out[1] = (nk_byte)tmp[1];
     out[2] = (nk_byte)tmp[2];
 }
-

+ 2 - 3
src/nuklear_combo.c

@@ -702,7 +702,7 @@ NK_API void nk_combo_close(struct nk_context *ctx)
     nk_contextual_close(ctx);
 }
 NK_API int
-nk_combo(struct nk_context *ctx, const char **items, int count,
+nk_combo(struct nk_context *ctx, const char *const *items, int count,
     int selected, int item_height, struct nk_vec2 size)
 {
     int i = 0;
@@ -820,7 +820,7 @@ nk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const c
     } return selected;
 }
 NK_API void
-nk_combobox(struct nk_context *ctx, const char **items, int count,
+nk_combobox(struct nk_context *ctx, const char *const *items, int count,
     int *selected, int item_height, struct nk_vec2 size)
 {
     *selected = nk_combo(ctx, items, count, *selected, item_height, size);
@@ -845,4 +845,3 @@ nk_combobox_callback(struct nk_context *ctx,
 {
     *selected = nk_combo_callback(ctx, item_getter, userdata,  *selected, count, item_height, size);
 }
-

+ 3 - 4
src/nuklear_draw.c

@@ -329,7 +329,7 @@ nk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,
     cmd->color = c;
 }
 NK_API void
-nk_stroke_polygon(struct nk_command_buffer *b,  float *points, int point_count,
+nk_stroke_polygon(struct nk_command_buffer *b, const float *points, int point_count,
     float line_thickness, struct nk_color col)
 {
     int i;
@@ -350,7 +350,7 @@ nk_stroke_polygon(struct nk_command_buffer *b,  float *points, int point_count,
     }
 }
 NK_API void
-nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
+nk_fill_polygon(struct nk_command_buffer *b, const float *points, int point_count,
     struct nk_color col)
 {
     int i;
@@ -371,7 +371,7 @@ nk_fill_polygon(struct nk_command_buffer *b, float *points, int point_count,
     }
 }
 NK_API void
-nk_stroke_polyline(struct nk_command_buffer *b, float *points, int point_count,
+nk_stroke_polyline(struct nk_command_buffer *b, const float *points, int point_count,
     float line_thickness, struct nk_color col)
 {
     int i;
@@ -555,4 +555,3 @@ nk_draw_text(struct nk_command_buffer *b, struct nk_rect r,
     NK_MEMCPY(cmd->string, string, (nk_size)length);
     cmd->string[length] = '\0';
 }
-

+ 1 - 2
src/nuklear_font.c

@@ -504,7 +504,7 @@ nk_font_query_font_glyph(nk_handle handle, float height,
 }
 #endif
 NK_API const struct nk_font_glyph*
-nk_font_find_glyph(struct nk_font *font, nk_rune unicode)
+nk_font_find_glyph(const struct nk_font *font, nk_rune unicode)
 {
     int i = 0;
     int count;
@@ -1370,4 +1370,3 @@ nk_font_atlas_clear(struct nk_font_atlas *atlas)
     nk_zero_struct(*atlas);
 }
 #endif
-

+ 3 - 4
src/nuklear_internal.h

@@ -186,7 +186,7 @@ enum nk_window_insert_location {
 NK_LIB void *nk_create_window(struct nk_context *ctx);
 NK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);
 NK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);
-NK_LIB struct nk_window *nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name);
+NK_LIB struct nk_window *nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name);
 NK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);
 
 /* pool */
@@ -206,7 +206,7 @@ NK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);
 NK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);
 NK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);
 NK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);
-NK_LIB nk_uint *nk_find_value(struct nk_window *win, nk_hash name);
+NK_LIB nk_uint *nk_find_value(const struct nk_window *win, nk_hash name);
 
 /* panel */
 NK_LIB void *nk_create_panel(struct nk_context *ctx);
@@ -227,7 +227,7 @@ NK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, flo
 NK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);
 NK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);
 NK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);
-NK_LIB void nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx);
+NK_LIB void nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx);
 
 /* popup */
 NK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);
@@ -375,4 +375,3 @@ nk_stbtt_free(void *ptr, void *user_data) {
 #endif /* NK_INCLUDE_FONT_BAKING */
 
 #endif
-

+ 8 - 8
src/nuklear_layout.c

@@ -134,7 +134,7 @@ nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
     win->layout->row.item_width = (float)width;
 }
 NK_API float
-nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width)
+nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width)
 {
     struct nk_window *win;
     NK_ASSERT(ctx);
@@ -463,7 +463,7 @@ nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
     layout->row.item = rect;
 }
 NK_API struct nk_rect
-nk_layout_space_bounds(struct nk_context *ctx)
+nk_layout_space_bounds(const struct nk_context *ctx)
 {
     struct nk_rect ret;
     struct nk_window *win;
@@ -482,7 +482,7 @@ nk_layout_space_bounds(struct nk_context *ctx)
     return ret;
 }
 NK_API struct nk_rect
-nk_layout_widget_bounds(struct nk_context *ctx)
+nk_layout_widget_bounds(const struct nk_context *ctx)
 {
     struct nk_rect ret;
     struct nk_window *win;
@@ -501,7 +501,7 @@ nk_layout_widget_bounds(struct nk_context *ctx)
     return ret;
 }
 NK_API struct nk_vec2
-nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
+nk_layout_space_to_screen(const struct nk_context *ctx, struct nk_vec2 ret)
 {
     struct nk_window *win;
     struct nk_panel *layout;
@@ -517,7 +517,7 @@ nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
     return ret;
 }
 NK_API struct nk_vec2
-nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
+nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 ret)
 {
     struct nk_window *win;
     struct nk_panel *layout;
@@ -533,7 +533,7 @@ nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
     return ret;
 }
 NK_API struct nk_rect
-nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
+nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect ret)
 {
     struct nk_window *win;
     struct nk_panel *layout;
@@ -549,7 +549,7 @@ nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
     return ret;
 }
 NK_API struct nk_rect
-nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret)
+nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect ret)
 {
     struct nk_window *win;
     struct nk_panel *layout;
@@ -730,7 +730,7 @@ nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
     layout->row.index++;
 }
 NK_LIB void
-nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx)
+nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx)
 {
     float y;
     int index;

+ 1 - 1
src/nuklear_popup.c

@@ -230,7 +230,7 @@ nk_popup_end(struct nk_context *ctx)
     nk_push_scissor(&win->buffer, win->layout->clip);
 }
 NK_API void
-nk_popup_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
+nk_popup_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
 {
     struct nk_window *popup;
 

+ 2 - 3
src/nuklear_string.c

@@ -419,14 +419,14 @@ nk_str_get_const(const struct nk_str *s)
     return (const char*)s->buffer.memory.ptr;
 }
 NK_API int
-nk_str_len(struct nk_str *s)
+nk_str_len(const struct nk_str *s)
 {
     NK_ASSERT(s);
     if (!s || !s->len || !s->buffer.allocated) return 0;
     return s->len;
 }
 NK_API int
-nk_str_len_char(struct nk_str *s)
+nk_str_len_char(const struct nk_str *s)
 {
     NK_ASSERT(s);
     if (!s || !s->len || !s->buffer.allocated) return 0;
@@ -446,4 +446,3 @@ nk_str_free(struct nk_str *str)
     nk_buffer_free(&str->buffer);
     str->len = 0;
 }
-

+ 1 - 2
src/nuklear_style.c

@@ -850,7 +850,7 @@ nk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,
     style->cursors[cursor] = c;
 }
 NK_API void
-nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors)
+nk_style_load_all_cursors(struct nk_context *ctx, const struct nk_cursor *cursors)
 {
     int i = 0;
     struct nk_style *style;
@@ -861,4 +861,3 @@ nk_style_load_all_cursors(struct nk_context *ctx, struct nk_cursor *cursors)
         style->cursors[i] = &cursors[i];
     style->cursor_visible = nk_true;
 }
-

+ 1 - 2
src/nuklear_table.c

@@ -71,7 +71,7 @@ nk_add_value(struct nk_context *ctx, struct nk_window *win,
     return &win->tables->values[win->tables->size++];
 }
 NK_LIB nk_uint*
-nk_find_value(struct nk_window *win, nk_hash name)
+nk_find_value(const struct nk_window *win, nk_hash name)
 {
     struct nk_table *iter = win->tables;
     while (iter) {
@@ -87,4 +87,3 @@ nk_find_value(struct nk_window *win, nk_hash name)
     }
     return 0;
 }
-

+ 9 - 9
src/nuklear_widget.c

@@ -7,7 +7,7 @@
  *
  * ===============================================================*/
 NK_API struct nk_rect
-nk_widget_bounds(struct nk_context *ctx)
+nk_widget_bounds(const struct nk_context *ctx)
 {
     struct nk_rect bounds;
     NK_ASSERT(ctx);
@@ -18,7 +18,7 @@ nk_widget_bounds(struct nk_context *ctx)
     return bounds;
 }
 NK_API struct nk_vec2
-nk_widget_position(struct nk_context *ctx)
+nk_widget_position(const struct nk_context *ctx)
 {
     struct nk_rect bounds;
     NK_ASSERT(ctx);
@@ -30,7 +30,7 @@ nk_widget_position(struct nk_context *ctx)
     return nk_vec2(bounds.x, bounds.y);
 }
 NK_API struct nk_vec2
-nk_widget_size(struct nk_context *ctx)
+nk_widget_size(const struct nk_context *ctx)
 {
     struct nk_rect bounds;
     NK_ASSERT(ctx);
@@ -42,7 +42,7 @@ nk_widget_size(struct nk_context *ctx)
     return nk_vec2(bounds.w, bounds.h);
 }
 NK_API float
-nk_widget_width(struct nk_context *ctx)
+nk_widget_width(const struct nk_context *ctx)
 {
     struct nk_rect bounds;
     NK_ASSERT(ctx);
@@ -54,7 +54,7 @@ nk_widget_width(struct nk_context *ctx)
     return bounds.w;
 }
 NK_API float
-nk_widget_height(struct nk_context *ctx)
+nk_widget_height(const struct nk_context *ctx)
 {
     struct nk_rect bounds;
     NK_ASSERT(ctx);
@@ -66,7 +66,7 @@ nk_widget_height(struct nk_context *ctx)
     return bounds.h;
 }
 NK_API nk_bool
-nk_widget_is_hovered(struct nk_context *ctx)
+nk_widget_is_hovered(const struct nk_context *ctx)
 {
     struct nk_rect c, v;
     struct nk_rect bounds;
@@ -88,7 +88,7 @@ nk_widget_is_hovered(struct nk_context *ctx)
     return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);
 }
 NK_API nk_bool
-nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn)
+nk_widget_is_mouse_clicked(const struct nk_context *ctx, enum nk_buttons btn)
 {
     struct nk_rect c, v;
     struct nk_rect bounds;
@@ -110,7 +110,7 @@ nk_widget_is_mouse_clicked(struct nk_context *ctx, enum nk_buttons btn)
     return nk_input_mouse_clicked(&ctx->input, btn, bounds);
 }
 NK_API nk_bool
-nk_widget_has_mouse_click_down(struct nk_context *ctx, enum nk_buttons btn, nk_bool down)
+nk_widget_has_mouse_click_down(const struct nk_context *ctx, enum nk_buttons btn, nk_bool down)
 {
     struct nk_rect c, v;
     struct nk_rect bounds;
@@ -182,7 +182,7 @@ nk_widget(struct nk_rect *bounds, const struct nk_context *ctx)
     return NK_WIDGET_VALID;
 }
 NK_API enum nk_widget_layout_states
-nk_widget_fitting(struct nk_rect *bounds, struct nk_context *ctx,
+nk_widget_fitting(struct nk_rect *bounds, const struct nk_context *ctx,
     struct nk_vec2 item_padding)
 {
     /* update the bounds to stand without padding  */

+ 16 - 16
src/nuklear_window.c

@@ -43,7 +43,7 @@ nk_free_window(struct nk_context *ctx, struct nk_window *win)
     nk_free_page_element(ctx, pe);}
 }
 NK_LIB struct nk_window*
-nk_find_window(struct nk_context *ctx, nk_hash hash, const char *name)
+nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name)
 {
     struct nk_window *iter;
     iter = ctx->begin;
@@ -352,7 +352,7 @@ nk_window_get_height(const struct nk_context *ctx)
     return ctx->current->bounds.h;
 }
 NK_API struct nk_rect
-nk_window_get_content_region(struct nk_context *ctx)
+nk_window_get_content_region(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -360,7 +360,7 @@ nk_window_get_content_region(struct nk_context *ctx)
     return ctx->current->layout->clip;
 }
 NK_API struct nk_vec2
-nk_window_get_content_region_min(struct nk_context *ctx)
+nk_window_get_content_region_min(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -369,7 +369,7 @@ nk_window_get_content_region_min(struct nk_context *ctx)
     return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);
 }
 NK_API struct nk_vec2
-nk_window_get_content_region_max(struct nk_context *ctx)
+nk_window_get_content_region_max(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -379,7 +379,7 @@ nk_window_get_content_region_max(struct nk_context *ctx)
         ctx->current->layout->clip.y + ctx->current->layout->clip.h);
 }
 NK_API struct nk_vec2
-nk_window_get_content_region_size(struct nk_context *ctx)
+nk_window_get_content_region_size(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -388,7 +388,7 @@ nk_window_get_content_region_size(struct nk_context *ctx)
     return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);
 }
 NK_API struct nk_command_buffer*
-nk_window_get_canvas(struct nk_context *ctx)
+nk_window_get_canvas(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -397,7 +397,7 @@ nk_window_get_canvas(struct nk_context *ctx)
     return &ctx->current->buffer;
 }
 NK_API struct nk_panel*
-nk_window_get_panel(struct nk_context *ctx)
+nk_window_get_panel(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -405,7 +405,7 @@ nk_window_get_panel(struct nk_context *ctx)
     return ctx->current->layout;
 }
 NK_API void
-nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
+nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)
 {
     struct nk_window *win;
     NK_ASSERT(ctx);
@@ -428,7 +428,7 @@ nk_window_has_focus(const struct nk_context *ctx)
     return ctx->current == ctx->active;
 }
 NK_API nk_bool
-nk_window_is_hovered(struct nk_context *ctx)
+nk_window_is_hovered(const struct nk_context *ctx)
 {
     NK_ASSERT(ctx);
     NK_ASSERT(ctx->current);
@@ -443,7 +443,7 @@ nk_window_is_hovered(struct nk_context *ctx)
     }
 }
 NK_API nk_bool
-nk_window_is_any_hovered(struct nk_context *ctx)
+nk_window_is_any_hovered(const struct nk_context *ctx)
 {
     struct nk_window *iter;
     NK_ASSERT(ctx);
@@ -470,14 +470,14 @@ nk_window_is_any_hovered(struct nk_context *ctx)
     return 0;
 }
 NK_API nk_bool
-nk_item_is_any_active(struct nk_context *ctx)
+nk_item_is_any_active(const struct nk_context *ctx)
 {
     int any_hovered = nk_window_is_any_hovered(ctx);
     int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);
     return any_hovered || any_active;
 }
 NK_API nk_bool
-nk_window_is_collapsed(struct nk_context *ctx, const char *name)
+nk_window_is_collapsed(const struct nk_context *ctx, const char *name)
 {
     int title_len;
     nk_hash title_hash;
@@ -492,7 +492,7 @@ nk_window_is_collapsed(struct nk_context *ctx, const char *name)
     return win->flags & NK_WINDOW_MINIMIZED;
 }
 NK_API nk_bool
-nk_window_is_closed(struct nk_context *ctx, const char *name)
+nk_window_is_closed(const struct nk_context *ctx, const char *name)
 {
     int title_len;
     nk_hash title_hash;
@@ -507,7 +507,7 @@ nk_window_is_closed(struct nk_context *ctx, const char *name)
     return (win->flags & NK_WINDOW_CLOSED);
 }
 NK_API nk_bool
-nk_window_is_hidden(struct nk_context *ctx, const char *name)
+nk_window_is_hidden(const struct nk_context *ctx, const char *name)
 {
     int title_len;
     nk_hash title_hash;
@@ -522,7 +522,7 @@ nk_window_is_hidden(struct nk_context *ctx, const char *name)
     return (win->flags & NK_WINDOW_HIDDEN);
 }
 NK_API nk_bool
-nk_window_is_active(struct nk_context *ctx, const char *name)
+nk_window_is_active(const struct nk_context *ctx, const char *name)
 {
     int title_len;
     nk_hash title_hash;
@@ -537,7 +537,7 @@ nk_window_is_active(struct nk_context *ctx, const char *name)
     return win == ctx->active;
 }
 NK_API struct nk_window*
-nk_window_find(struct nk_context *ctx, const char *name)
+nk_window_find(const struct nk_context *ctx, const char *name)
 {
     int title_len;
     nk_hash title_hash;

+ 1 - 1
src/paq.bat

@@ -1 +1 @@
-build.py --macro NK --intro HEADER --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ..\nuklear.h
+build.py --macro NK --intro HEADER.md --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ..\nuklear.h

+ 1 - 1
src/paq.sh

@@ -1,2 +1,2 @@
 #!/bin/sh
-python build.py --macro NK --intro HEADER --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ../nuklear.h
+python3 build.py --macro NK --intro HEADER.md --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ../nuklear.h

Some files were not shown because too many files changed in this diff