Browse Source

Release Version 1.0

This is the first release version of nuklear (previously: zahnrad).
As for those who no the old version will notice: a lot has changed.

Most obvious should be the two biggest changes. First the name change
because I got critique that the name is hard to comprehend and
remember (understandable for non-germans) and the second is the
transistion from four files (zahnrad.h, zahnrad.c, stb_truetype
and stb_rect_pack) to one single header library file nuklear.h.
I am not 100% convinced that using a single header library is the
right choice here but so far I haven't encountered any problems.

Noticable should be as well that nuklear now directly embeds three
stb libraries: stb_truetype, stb_rect_pack and stb_textedit. Like
in previous versions the first two are optional and the library
can be compiled without. stb_textedit on the other hand powers
the text edit implementation for single as well as multiline
text manipulation. The text edit implementation is still relative
new and untested so you can expect some bugs I have not found yet.

In the demo department a lot changed as well. All platform demos
now don't compile one big demo but instead contain a simple
demo and small abstraction layer over the platform. Main benefit is
better understandablity improved ease of use. The old demo
is now split up and transfered into the example folder while each part
is self contained and compileable. (All examples use glfw I don't now
if this is the best platform but it is at least the simplest.
I also removed the apple demo because I don't have an apple system
and cannot make sure the new version runs with the old version.

Finally a lot of small bugs have been fixed as well as bugs found by
clang analyzer and coverity.
vurtun 9 years ago
parent
commit
b2c87ed7c0
100 changed files with 6499 additions and 9566 deletions
  1. 0 43
      CONTRIBUTING.md
  2. 0 17
      LICENSE
  3. 98 44
      Readme.md
  4. 0 1
      demo/Readme.md
  5. 1 1
      demo/allegro5/Makefile
  6. 0 337
      demo/allegro5/allegro.c
  7. 131 0
      demo/allegro5/main.c
  8. 271 0
      demo/allegro5/nuklear_allegro.c
  9. 17 0
      demo/allegro5/nuklear_allegro.h
  10. 0 53
      demo/apple/.gitignore
  11. 0 293
      demo/apple/Mac_GL.xcodeproj/project.pbxproj
  12. 0 7
      demo/apple/Mac_GL.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  13. 0 32
      demo/apple/Mac_GL/Info.plist
  14. 0 400
      demo/apple/Mac_GL/main.m
  15. 0 19
      demo/apple/README.md
  16. 0 81
      demo/apple/ZahnradBackend.h
  17. 0 767
      demo/apple/ZahnradBackend.m
  18. 0 16
      demo/apple/ZahnradBackend.xcworkspace/contents.xcworkspacedata
  19. 0 275
      demo/apple/iOS_CoreGraphics.xcodeproj/project.pbxproj
  20. 0 7
      demo/apple/iOS_CoreGraphics.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  21. 0 50
      demo/apple/iOS_CoreGraphics/Info.plist
  22. 0 341
      demo/apple/iOS_CoreGraphics/main.m
  23. 0 296
      demo/apple/iOS_GL_ES.xcodeproj/project.pbxproj
  24. 0 7
      demo/apple/iOS_GL_ES.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  25. 0 48
      demo/apple/iOS_GL_ES/Info.plist
  26. 0 225
      demo/apple/iOS_GL_ES/main.m
  27. 0 292
      demo/apple/tvOS_GL_ES.xcodeproj/project.pbxproj
  28. 0 7
      demo/apple/tvOS_GL_ES.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  29. 0 32
      demo/apple/tvOS_GL_ES/Info.plist
  30. 0 254
      demo/apple/tvOS_GL_ES/main.m
  31. 0 2676
      demo/demo.c
  32. 1 1
      demo/glfw/Makefile
  33. 0 591
      demo/glfw/glfw.c
  34. 139 0
      demo/glfw/main.c
  35. 374 0
      demo/glfw/nuklear_glfw.c
  36. 23 0
      demo/glfw/nuklear_glfw.h
  37. 0 26
      demo/linuxgl/Makefile
  38. 0 963
      demo/linuxgl/linuxgl.c
  39. 1 1
      demo/sdl/Makefile
  40. 142 0
      demo/sdl/main.c
  41. 369 0
      demo/sdl/nuklear_sdl.c
  42. 18 0
      demo/sdl/nuklear_sdl.h
  43. 0 568
      demo/sdl/sdl.c
  44. 1 1
      demo/x11/Makefile
  45. 167 0
      demo/x11/main.c
  46. 611 0
      demo/x11/nuklear_xlib.c
  47. 17 0
      demo/x11/nuklear_xlib.h
  48. 0 794
      demo/x11/xlib.c
  49. 34 0
      example/Makefile
  50. 882 0
      example/extended.c
  51. 889 0
      example/file_browser.c
  52. 0 0
      example/icon/checked.png
  53. 0 0
      example/icon/cloud.png
  54. 0 0
      example/icon/computer.png
  55. 0 0
      example/icon/copy.png
  56. 0 0
      example/icon/default.png
  57. 0 0
      example/icon/delete.png
  58. 0 0
      example/icon/desktop.png
  59. 0 0
      example/icon/directory.png
  60. 0 0
      example/icon/edit.png
  61. 0 0
      example/icon/export.png
  62. 0 0
      example/icon/font.png
  63. 0 0
      example/icon/home.png
  64. 0 0
      example/icon/img.png
  65. 0 0
      example/icon/movie.png
  66. 0 0
      example/icon/music.png
  67. 0 0
      example/icon/next.png
  68. 0 0
      example/icon/pause.png
  69. 0 0
      example/icon/pen.png
  70. 0 0
      example/icon/phone.png
  71. 0 0
      example/icon/plane.png
  72. 0 0
      example/icon/play.png
  73. 0 0
      example/icon/prev.png
  74. 0 0
      example/icon/rocket.png
  75. 0 0
      example/icon/settings.png
  76. 0 0
      example/icon/stop.png
  77. 0 0
      example/icon/text.png
  78. 0 0
      example/icon/tools.png
  79. 0 0
      example/icon/unchecked.png
  80. 0 0
      example/icon/volume.png
  81. 0 0
      example/icon/wifi.png
  82. 0 0
      example/images/image1.png
  83. 0 0
      example/images/image2.png
  84. 0 0
      example/images/image3.png
  85. 0 0
      example/images/image4.png
  86. 0 0
      example/images/image5.png
  87. 0 0
      example/images/image6.png
  88. 0 0
      example/images/image7.png
  89. 0 0
      example/images/image8.png
  90. 0 0
      example/images/image9.png
  91. 715 0
      example/node_editor.c
  92. 1466 0
      example/overview.c
  93. 0 0
      example/stb_image.h
  94. 132 0
      example/style.c
  95. BIN
      extra_font/Cousine-Regular.ttf
  96. 0 0
      extra_font/DroidSans.ttf
  97. BIN
      extra_font/Karla-Regular.ttf
  98. BIN
      extra_font/ProggyClean.ttf
  99. BIN
      extra_font/ProggyTiny.ttf
  100. BIN
      extra_font/Raleway-Bold.ttf

+ 0 - 43
CONTRIBUTING.md

@@ -1,43 +0,0 @@
-CONTRIBUTING
-============
-## Submitting changes
-Please send a GitHub Pull Request with a clear list of what you've done (read more about [pull requests](http://help.github.com/pull-requests/)). 
-
-## Features
-If you have an idea for new features just [open an issue](https://github.com/vurtun/zahnrad/issues) with your suggestion.
-  * Find and correct spelling mistakes
-  * Add (insert your favorite platform or render backend here) demo implementation (some possibilities: DirectX 9/DirectX 10/DirectX 11 and win32 with OpenGL)
-  * Add clipboard user callbacks back into all demos
-  * Add additional widgets
-  * Find a better way to change the style or group style options
-  * Add support for multiple pointers for touch input devices (probably requires to rewrite mouse handling in `struct zr_input`)
-  * Extend xlib demo to support image drawing with arbitrary image width and height
-  * Change cursor in `zr_widget_edit_box` and `zr_widget_edit_field` to thin standard cursor version used in editors
-  * Extend piemenu to support submenus (another ring around the first ring or something like [this:](http://gdj.gdj.netdna-cdn.com/wp-content/uploads/2013/02/ui+concepts+13.gif)) and turn it into a default library widget.
-  * Add label describing the currently active piemenu entry
-  * Add tables with scaleable column width
-  * Rewrite the chart API to support a better range of charts (maybe take notes from Javascript chart frameworks) 
-  * Create an API to allow scaling between groups (maybe extend and convert the demo example)
-  * Come up with a better way to provide and create widget and window styles
-  * Add multiple Tab support (maybe use `zr_group` and add a header)  
-  * Extend context to not only support overlapping windows but tiled windows as well
-
-## Bugs
-  * Seperator widget is currently bugged and does not work as intended
-  * Text handling is still a little bit janky and probably needs to be further tested and polished
-  * `zr_edit_buffer` with multiline flag is bugged for '\n', need to differentiate between visible and non-visible characters
-
-## Coding conventions
-  * Only use C89 (ANSI C)
-  * Do not use any compiler specific extensions
-  * For indent use four spaces
-  * Do not typedef structs, unions and enums
-  * Variable, object and function names should always be lowercase and use underscores instead of camel case
-  * Whitespace after for, while, if, do and switch
-  * Always use parentheses if you use the sizeof operator (e.g: sizeof(struct zr_context) and not sizeof struct zr_context)
-  * Beginning braces on the new line for functions and on the same line otherwise.
-  * If function becomes to big either a.) create a subblock inside the function and comment or b.) write a functional function 
-  * Only use fixed size types (zr_uint, zr_size, ...) if you really need to and use basic types otherwise
-  * Do not include any header files in either zahnrad.h or zahnrad.c
-  * Do not add dependencies rather write your own version if possible
-  * Write correct commit messages: (http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 

+ 0 - 17
LICENSE

@@ -1,17 +0,0 @@
-Copyright (c) 2016 Micha Mettke
-
-This software is provided 'as-is', without any express or implied
-warranty.  In no event will the authors be held liable for any damages
-arising from the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-1.  The origin of this software must not be misrepresented; you must not
-    claim that you wrote the original software. If you use this software
-    in a product, an acknowledgment in the product documentation would be
-    appreciated but is not required.
-2.  Altered source versions must be plainly marked as such, and must not be
-    misrepresented as being the original software.
-3.  This notice may not be removed or altered from any source distribution.

+ 98 - 44
Readme.md

@@ -1,9 +1,7 @@
-# Zahnrad
-[![Coverity Status](https://scan.coverity.com/projects/5863/badge.svg)](https://scan.coverity.com/projects/5863)
-
+# Nuklear
 This is a minimal state immediate mode graphical user interface toolkit
-written in ANSI C and licensed under zlib. It was designed as a simple embeddable user interface for
-application and does not have any direct dependencies,
+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
@@ -12,34 +10,30 @@ render backends it only focuses on the actual UI.
 
 ## Features
 - Immediate mode graphical user interface toolkit
+- Single header library
 - Written in C89 (ANSI C)
-- Small codebase (~12kLOC)
+- Small codebase (~15kLOC)
 - Focus on portability, efficiency and simplicity
-- No dependencies (not even the standard library)
-- No global or hidden state
+- 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
-
-## Optional
-- Vertex buffer output 
-- Font handling
+- No global or hidden state
+- Customizeable library modules (you can compile and use only what you need)
+- Optional font baker and vertex buffer output
 
 ## Building
-The library is self-contained within four different files that only have to be
-copied and compiled into your application. Files zahnrad.c and zahnrad.h make up
-the core of the library, while stb_rect_pack.h and stb_truetype.h are
-for a optional font handling implementation and can be removed if not needed.
-- zahnrad.c
-- zahnrad.h
-- stb_rect_pack.h (optional)
-- stb_truetype.h (optional)
-
-There are no dependencies or a particular building process required. You just have
-to compile the .c file and #include zahnrad.h into your project. To actually
-run you have to provide the input state, configuration style and memory
-for draw commands to the library. After the GUI was executed all draw commands
-have to be either executed or optionally converted into a vertex buffer to
-draw the GUI.
+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.
+
+The implementation mode requires to define  the preprocessor macro
+`NK_IMPLEMENTATION` in *one* .c/.cpp file before #includeing this file, e.g.:
+```c
+    #define NK_IMPLEMENTATION
+    #include "nuklear.h"
+```
 
 ## Gallery
 ![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
@@ -51,40 +45,100 @@ draw the GUI.
 ## Example
 ```c
 /* init gui state */
-struct zr_context ctx;
-zr_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
+struct nk_context ctx;
+nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
 
 enum {EASY, HARD};
 int op = EASY;
 float value = 0.6f;
 int i =  20;
 
-struct zr_panel layout;
-zr_begin(&ctx, &layout, "Show", zr_rect(50, 50, 220, 220),
-    ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_CLOSEABLE);
+struct nk_panel layout;
+nk_begin(&ctx, &layout, "Show", nk_rect(50, 50, 220, 220),
+    NK_WINDOW_BORDER|NK_WINDOW_MOVEABLE|NK_WINDOW_CLOSEABLE);
 {
     /* fixed widget pixel width */
-    zr_layout_row_static(&ctx, 30, 80, 1);
-    if (zr_button_text(&ctx, "button", ZR_BUTTON_DEFAULT)) {
+    nk_layout_row_static(&ctx, 30, 80, 1);
+    if (nk_button_text(&ctx, "button", NK_BUTTON_DEFAULT)) {
         /* event handling */
     }
 
     /* fixed widget window ratio width */
-    zr_layout_row_dynamic(&ctx, 30, 2);
-    if (zr_option(&ctx, "easy", op == EASY)) op = EASY;
-    if (zr_option(&ctx, "hard", op == HARD)) op = HARD;
+    nk_layout_row_dynamic(&ctx, 30, 2);
+    if (nk_option(&ctx, "easy", op == EASY)) op = EASY;
+    if (nk_option(&ctx, "hard", op == HARD)) op = HARD;
 
     /* custom widget pixel width */
-    zr_layout_row_begin(&ctx, ZR_STATIC, 30, 2);
+    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
     {
-        zr_layout_row_push(&ctx, 50);
-        zr_label(&ctx, "Volume:", ZR_TEXT_LEFT);
-        zr_layout_row_push(&ctx, 110);
-        zr_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
+        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);
     }
-    zr_layout_row_end(&ctx);
+    nk_layout_row_end(&ctx);
 }
-zr_end(ctx);
+nk_end(ctx);
 ```
 ![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
 
+
+##FAQ
+---
+#### Why single-file headers?
+Windows doesn't have standard directories where libraries
+live. That makes deploying libraries in Windows a lot more
+painful than open source developers on Unix-derivates generally
+realize. (It also makes library dependencies a lot worse in Windows.)
+
+There's also a common problem in Windows where a library was built
+against a different version of the runtime library, which causes
+link conflicts and confusion. Shipping the libs as headers means
+you normally just compile them straight into your project without
+making libraries, thus sidestepping that problem.
+
+Making them a single file makes it very easy to just
+drop them into a project that needs them. (Of course you can
+still put them in a proper shared library tree if you want.)
+
+Why not two files, one a header and one an implementation?
+The difference between 10 files and 9 files is not a big deal,
+but the difference between 2 files and 1 file is a big deal.
+You don't need to zip or tar the files up, you don't have to
+remember to attach *two* files, etc.
+
+#### Where is the documentation?
+Each file has documentation, basic ussage description and
+examples at the top of the file. In addition each API function,
+struct and member variables are documented as well.
+Finally each library has a corresponding test file inside the
+test directory for additional working examples.
+
+#### Why C?
+Personally I primarily use C instead of C++ and since I want to
+support both C and C++ and C++ is not useable from C I therefore focus
+on C.
+
+#### Why C89?
+I use C89 instead of C99/C11 for its portability between different compilers
+and accessiblity for other languages.
+
+##CREDITS:
+Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
+
+
+Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain)
+Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
+
+
+Big thank you to Omar Cornut (ocornut@github) for his imgui library 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 by faith
+in libraries and brought me to create some of my own.
+
+##LICENSE:
+This software is dual-licensed to the public domain and under the following
+license: you are granted a perpetual, irrevocable license to copy, modify,
+publish and distribute this file as you see fit.
+

+ 0 - 1
demo/Readme.md

@@ -1 +0,0 @@
-# Demo

+ 1 - 1
demo/allegro5/Makefile

@@ -8,7 +8,7 @@ DCC = gcc
 # Flags
 CFLAGS = -std=c89 -pedantic
 
-SRC = ../../zahnrad.c allegro.c
+SRC = main.c
 OBJ = $(SRC:.c=.o)
 
 ifeq ($(OS),Windows_NT)

+ 0 - 337
demo/allegro5/allegro.c

@@ -1,337 +0,0 @@
-/*
-    Copyright (c) 2016 Micha Mettke
-
-    This software is provided 'as-is', without any express or implied
-    warranty.  In no event will the authors be held liable for any damages
-    arising from the use of this software.
-
-    Permission is granted to anyone to use this software for any purpose,
-    including commercial applications, and to alter it and redistribute it
-    freely, subject to the following restrictions:
-
-    1.  The origin of this software must not be misrepresented; you must not
-        claim that you wrote the original software. If you use this software
-        in a product, an acknowledgment in the product documentation would be
-        appreciated but is not required.
-    2.  Altered source versions must be plainly marked as such, and must not be
-        misrepresented as being the original software.
-    3.  This notice may not be removed or altered from any source distribution.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include <math.h>
-
-#include <allegro5/allegro.h>
-#include <allegro5/allegro_primitives.h>
-
-/* macros */
-#define MAX_VERTEX_MEMORY 512 * 1024
-#define MAX_ELEMENT_MEMORY 128 * 1024
-
-#define DEMO_DO_NOT_DRAW_IMAGES
-#include "../../zahnrad.h"
-#include "../demo.c"
-
-struct device {
-    ALLEGRO_DISPLAY *display;
-    ALLEGRO_EVENT_QUEUE *queue;
-    ALLEGRO_BITMAP *texture;
-    ALLEGRO_VERTEX_DECL *vertex_decl;
-    struct zr_draw_null_texture null;
-    struct zr_buffer cmds;
-    void *vertex_buffer;
-    void *element_buffer;
-};
-
-struct allegro_vertex {
-    struct zr_vec2 pos;
-    struct zr_vec2 uv;
-    ALLEGRO_COLOR col;
-};
-
-static void
-die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fputs("\n", stderr);
-    exit(EXIT_FAILURE);
-}
-
-static char*
-file_load(const char* path, size_t* siz)
-{
-    char *buf;
-    FILE *fd = fopen(path, "rb");
-    if (!fd) die("Failed to open file: %s\n", path);
-    fseek(fd, 0, SEEK_END);
-    *siz = (size_t)ftell(fd);
-    fseek(fd, 0, SEEK_SET);
-    buf = (char*)calloc(*siz, 1);
-    fread(buf, *siz, 1, fd);
-    fclose(fd);
-    return buf;
-}
-
-static void
-device_init(struct device *dev)
-{
-    ALLEGRO_VERTEX_ELEMENT elems[] = {
-        {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, pos)},
-        {ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, uv)},
-        {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(struct allegro_vertex, col)},
-        {0,0,0}
-    };
-    dev->vertex_decl = al_create_vertex_decl(elems, sizeof(struct allegro_vertex));
-
-    /* allocate memory for drawing process */
-    dev->vertex_buffer = calloc(MAX_VERTEX_MEMORY, 1);
-    dev->element_buffer = calloc(MAX_ELEMENT_MEMORY, 1);
-}
-
-static void
-device_shutdown(struct device *dev)
-{
-    free(dev->vertex_buffer);
-    free(dev->element_buffer);
-    zr_buffer_free(&dev->cmds);
-}
-
-static void
-device_upload_atlas(struct device *dev, const void *image, int width, int height)
-{
-    /* create allegro font bitmap */
-    ALLEGRO_BITMAP *bitmap = 0;
-    int flags = al_get_new_bitmap_flags();
-    int fmt = al_get_new_bitmap_format();
-    al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR);
-    al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
-    bitmap = al_create_bitmap(width, height);
-    al_set_new_bitmap_flags(flags);
-    al_set_new_bitmap_format(fmt);
-    assert(bitmap);
-
-    {
-        /* copy font texture into bitmap */
-        ALLEGRO_LOCKED_REGION * locked_img;
-        locked_img = al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_WRITEONLY);
-        assert(locked_img);
-        memcpy(locked_img->data, image, sizeof(uint32_t)*(size_t)(width*height));
-        al_unlock_bitmap(bitmap);
-    }
-
-    /* convert software texture into hardware texture */
-    dev->texture = al_clone_bitmap(bitmap);
-    al_destroy_bitmap(bitmap);
-    assert(dev->texture);
-}
-
-static void
-device_draw(struct device *dev, struct zr_context *ctx, enum zr_anti_aliasing AA)
-{
-    int op, src, dst;
-    al_get_blender(&op, &src, &dst);
-    al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
-
-    {
-        const struct zr_draw_command *cmd;
-        struct zr_buffer vbuf, ebuf;
-        int offset = 0;
-        struct allegro_vertex *vertices = 0;
-        int *indicies = 0;
-
-        /* fill converting configuration */
-        struct zr_convert_config config;
-        memset(&config, 0, sizeof(config));
-        config.global_alpha = 1.0f;
-        config.shape_AA = AA;
-        config.line_AA = AA;
-        config.circle_segment_count = 22;
-        config.arc_segment_count = 22;
-        config.curve_segment_count = 22;
-        config.null = dev->null;
-
-        /* convert from command into hardware format */
-        zr_buffer_init_fixed(&vbuf, dev->vertex_buffer, MAX_VERTEX_MEMORY);
-        zr_buffer_init_fixed(&ebuf, dev->element_buffer, MAX_ELEMENT_MEMORY);
-            zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
-
-        {
-            /* <sign> allegro does not support 32-bit packed color */
-            unsigned int i = 0;
-            struct zr_draw_vertex *verts = (struct zr_draw_vertex*)dev->vertex_buffer;
-            vertices = calloc(sizeof(struct allegro_vertex), ctx->canvas.vertex_count);
-            for (i = 0; i < ctx->canvas.vertex_count; ++i) {
-                zr_byte *c;
-                vertices[i].pos = verts[i].position;
-                vertices[i].uv = verts[i].uv;
-                c = (zr_byte*)&verts[i].col;
-                vertices[i].col = al_map_rgba(c[0], c[1], c[2], c[3]);
-            }
-        }
-        {
-            /* <massive sign> allegro does not support 16-bit indicies:
-             * @OPT: define zr_draw_index as int to fix this issue. */
-            unsigned int i = 0;
-            zr_draw_index *elements = (zr_draw_index*)dev->element_buffer;
-            indicies = calloc(sizeof(int), ctx->canvas.element_count);
-            for (i = 0; i < ctx->canvas.element_count; ++i)
-                indicies[i] = elements[i];
-        }
-
-        /* iterate over and execute each draw command */
-        zr_draw_foreach(cmd, ctx, &dev->cmds)
-        {
-            ALLEGRO_BITMAP *texture = cmd->texture.ptr;
-            if (!cmd->elem_count) continue;
-            al_set_clipping_rectangle((int)cmd->clip_rect.x, (int)cmd->clip_rect.y,
-                (int)cmd->clip_rect.w, (int)cmd->clip_rect.h);
-            al_draw_indexed_prim(vertices, dev->vertex_decl, texture, &indicies[offset],
-                (int)cmd->elem_count, ALLEGRO_PRIM_TRIANGLE_LIST);
-            offset += cmd->elem_count;
-        }
-
-        free(vertices);
-        free(indicies);
-        zr_clear(ctx);
-    }
-    al_set_blender(op, src, dst);
-    al_set_clipping_rectangle(0,0,al_get_display_width(dev->display),
-        al_get_display_height(dev->display));
-}
-
-static void
-input_key(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down)
-{
-    int sym = evt->keyboard.keycode;
-    if (sym == ALLEGRO_KEY_RSHIFT || sym == ALLEGRO_KEY_LSHIFT)
-        zr_input_key(ctx, ZR_KEY_SHIFT, down);
-    else if (sym == ALLEGRO_KEY_DELETE)
-        zr_input_key(ctx, ZR_KEY_DEL, down);
-    else if (sym == ALLEGRO_KEY_ENTER)
-        zr_input_key(ctx, ZR_KEY_ENTER, down);
-    else if (sym == ALLEGRO_KEY_TAB)
-        zr_input_key(ctx, ZR_KEY_TAB, down);
-    else if (sym == ALLEGRO_KEY_BACKSPACE)
-        zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
-    else if (sym == ALLEGRO_KEY_LEFT)
-        zr_input_key(ctx, ZR_KEY_LEFT, down);
-    else if (sym == ALLEGRO_KEY_RIGHT)
-        zr_input_key(ctx, ZR_KEY_RIGHT, down);
-    else if (sym == ALLEGRO_KEY_C)
-        zr_input_key(ctx, ZR_KEY_COPY, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
-    else if (sym == ALLEGRO_KEY_V)
-        zr_input_key(ctx, ZR_KEY_PASTE, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
-    else if (sym == ALLEGRO_KEY_X)
-        zr_input_key(ctx, ZR_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
-}
-
-static void
-input_button(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down)
-{
-    const int x = evt->mouse.x;
-    const int y = evt->mouse.y;
-    if (evt->mouse.button == 1)
-        zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
-    if (evt->mouse.button == 2)
-        zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
-}
-
-int
-main(int argc, char *argv[])
-{
-    struct device dev;
-    int running = 1;
-
-    struct demo gui;
-    struct zr_font *font;
-    struct zr_font_atlas atlas;
-    const char *font_path = (argc > 1) ? argv[1]: 0;
-
-    /* Allegro */
-    al_init();
-    al_install_keyboard();
-    al_install_mouse();
-    al_init_primitives_addon();
-    dev.display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
-    al_set_window_title(dev.display, "Zahnrad");
-    dev.queue = al_create_event_queue();
-    al_register_event_source(dev.queue, al_get_display_event_source(dev.display));
-    al_register_event_source(dev.queue, al_get_keyboard_event_source());
-    al_register_event_source(dev.queue, al_get_mouse_event_source());
-
-    device_init(&dev);
-    {
-        /* Font */
-        const void *image;
-        int width, height;
-
-        zr_font_atlas_init_default(&atlas);
-        zr_font_atlas_begin(&atlas);
-        if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
-        else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
-        image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
-        device_upload_atlas(&dev, image, width, height);
-        zr_font_atlas_end(&atlas, zr_handle_ptr(dev.texture), &dev.null);
-
-        /* GUI */
-        memset(&gui, 0, sizeof(gui));
-        zr_buffer_init_default(&dev.cmds);
-        zr_init_default(&gui.ctx, &font->handle);
-    }
-
-
-    while (running) {
-        /* Input */
-        ALLEGRO_EVENT evt;
-        zr_input_begin(&gui.ctx);
-        while (al_get_next_event(dev.queue, &evt)) {
-            if (evt.type == ALLEGRO_EVENT_DISPLAY_CLOSE) goto cleanup;
-            else if (evt.type == ALLEGRO_EVENT_KEY_UP && evt.keyboard.display == dev.display)
-                input_key(&gui.ctx, &evt, zr_false);
-            else if (evt.type == ALLEGRO_EVENT_KEY_DOWN && evt.keyboard.display == dev.display)
-                input_key(&gui.ctx, &evt, zr_true);
-            else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
-                input_button(&gui.ctx, &evt, zr_true);
-            else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
-                input_button(&gui.ctx, &evt, zr_false);
-            else if (evt.type == ALLEGRO_EVENT_MOUSE_AXES) {
-                zr_input_motion(&gui.ctx, evt.mouse.x, evt.mouse.y);
-            } else if (evt.type == ALLEGRO_EVENT_KEY_CHAR) {
-                if (evt.keyboard.display == dev.display)
-                    if (evt.keyboard.unichar > 0 && evt.keyboard.unichar < 0x10000)
-                        zr_input_unicode(&gui.ctx, (zr_rune)evt.keyboard.unichar);
-            }
-        }
-        zr_input_end(&gui.ctx);
-
-        /* GUI */
-        running = run_demo(&gui);
-
-        /* Draw */
-        al_clear_to_color(al_map_rgba_f(0.2f, 0.2f, 0.2f, 1.0f));
-        device_draw(&dev, &gui.ctx, ZR_ANTI_ALIASING_ON);
-        al_flip_display();
-    }
-
-cleanup:
-    /* Cleanup */
-    if (dev.texture)
-        al_destroy_bitmap(dev.texture);
-    if (dev.queue)
-        al_destroy_event_queue(dev.queue);
-    if (dev.display)
-        al_destroy_display(dev.display);
-    zr_font_atlas_clear(&atlas);
-    device_shutdown(&dev);
-    zr_free(&gui.ctx);
-    return 0;
-}
-

+ 131 - 0
demo/allegro5/main.c

@@ -0,0 +1,131 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+
+#include <allegro5/allegro.h>
+#include <allegro5/allegro_primitives.h>
+
+/* macros */
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+/* these defines are both needed for the header
+ * and source file. So if you split them remember
+ * to copy them as well. */
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#include "nuklear_allegro.h"
+#include "nuklear_allegro.c"
+
+int
+main(void)
+{
+    int running = 1;
+    struct nk_context *ctx;
+    struct nk_color background;
+    ALLEGRO_DISPLAY *display;
+    ALLEGRO_EVENT_QUEUE *queue;
+
+    /* Allegro */
+    al_init();
+    al_install_keyboard();
+    al_install_mouse();
+    al_init_primitives_addon();
+    display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
+    al_set_window_title(display, "nuklear");
+
+    queue = al_create_event_queue();
+    al_register_event_source(queue, al_get_display_event_source(display));
+    al_register_event_source(queue, al_get_keyboard_event_source());
+    al_register_event_source(queue, al_get_mouse_event_source());
+
+    ctx = nk_allegro_init(display, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    {struct nk_font_atlas *atlas;
+    nk_allegro_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-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_allegro_font_stash_end();
+    /*nk_style_set_font(ctx, &droid->handle);*/}
+
+    background = nk_rgb(28,48,62);
+    while (running)
+    {
+        /* Input */
+        ALLEGRO_EVENT evt;
+        nk_input_begin(ctx);
+        while (al_get_next_event(queue, &evt)) {
+            if (evt.type == ALLEGRO_EVENT_DISPLAY_CLOSE) goto cleanup;
+            nk_allegro_handle_event(&evt);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        {struct nk_panel layout;
+        if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 200, 200),
+            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", NK_BUTTON_DEFAULT))
+                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, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            {struct nk_panel combo;
+            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, &combo, background, 400)) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }}
+        }
+        nk_end(ctx);}
+
+        /* Draw */
+        {float bg[4];
+        nk_color_fv(bg, background);
+        al_clear_to_color(al_map_rgba_f(bg[0], bg[1], bg[2], bg[3]));
+        nk_allegro_render(NK_ANTI_ALIASING_ON);
+        al_flip_display();}
+    }
+
+cleanup:
+    /* Cleanup */
+    if (queue) al_destroy_event_queue(queue);
+    if (display) al_destroy_display(display);
+    nk_allegro_shutdown();
+    return 0;
+}
+

+ 271 - 0
demo/allegro5/nuklear_allegro.c

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

+ 17 - 0
demo/allegro5/nuklear_allegro.h

@@ -0,0 +1,17 @@
+#ifndef NK_ALLEGRO_H_
+#define NK_ALLEGRO_H_
+
+#include "../../nuklear.h"
+
+NK_API struct nk_context* nk_allegro_init(ALLEGRO_DISPLAY *win, int max_vertex_memory, int max_element_memory);
+NK_API void nk_allegro_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_allegro_font_stash_end(void);
+
+NK_API void nk_allegro_handle_event(ALLEGRO_EVENT *evt);
+NK_API void nk_allegro_render(enum nk_anti_aliasing);
+NK_API void nk_allegro_shutdown(void);
+
+NK_API void nk_allegro_device_destroy(void);
+NK_API void nk_allegro_device_create(int max_vertex_memory, int max_elemnt_memory);
+
+#endif

+ 0 - 53
demo/apple/.gitignore

@@ -1,53 +0,0 @@
-# Xcode
-#
-# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
-
-## Build generated
-build/
-DerivedData
-
-## Various settings
-*.pbxuser
-!default.pbxuser
-*.mode1v3
-!default.mode1v3
-*.mode2v3
-!default.mode2v3
-*.perspectivev3
-!default.perspectivev3
-xcuserdata
-
-## Other
-*.xccheckout
-*.moved-aside
-*.xcuserstate
-*.xcscmblueprint
-
-## Obj-C/Swift specific
-*.hmap
-*.ipa
-
-# CocoaPods
-#
-# We recommend against adding the Pods directory to your .gitignore. However
-# you should judge for yourself, the pros and cons are mentioned at:
-# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
-#
-# Pods/
-
-# Carthage
-#
-# Add this line if you want to avoid checking in source code from Carthage dependencies.
-# Carthage/Checkouts
-
-Carthage/Build
-
-# fastlane
-#
-# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 
-# screenshots whenever they are needed.
-# For more information about the recommended setup visit:
-# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
-
-fastlane/report.xml
-fastlane/screenshots

+ 0 - 293
demo/apple/Mac_GL.xcodeproj/project.pbxproj

@@ -1,293 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		500B20241C4B41870002B53F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20231C4B41870002B53F /* main.m */; };
-		500B20401C4B43930002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B203F1C4B43930002B53F /* ZahnradBackend.m */; };
-		500B20421C4B43A30002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B20411C4B43A30002B53F /* zahnrad.c */; };
-		500B20481C4B43BC0002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20441C4B43BC0002B53F /* DroidSans.ttf */; };
-		500B20491C4B43BC0002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */; };
-		500B204A1C4B43BC0002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20461C4B43BC0002B53F /* Roboto-Light.ttf */; };
-		500B204B1C4B43BC0002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		500B201C1C4B41870002B53F /* Mac_GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mac_GL.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		500B20231C4B41870002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
-		500B202A1C4B41880002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		500B203E1C4B43930002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B203F1C4B43930002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B20411C4B43A30002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 5; };
-		500B20441C4B43BC0002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
-		500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
-		500B20461C4B43BC0002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
-		500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
-		504DFDEA1C4EA2CD00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
-		504DFDED1C4EA34800D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		500B20191C4B41870002B53F /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		500B20131C4B41870002B53F = {
-			isa = PBXGroup;
-			children = (
-				500B201E1C4B41870002B53F /* Mac_GL */,
-				500B20431C4B43BC0002B53F /* font */,
-				500B201D1C4B41870002B53F /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		500B201D1C4B41870002B53F /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				500B201C1C4B41870002B53F /* Mac_GL.app */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		500B201E1C4B41870002B53F /* Mac_GL */ = {
-			isa = PBXGroup;
-			children = (
-				504DFDED1C4EA34800D3714A /* demo.c */,
-				500B203E1C4B43930002B53F /* ZahnradBackend.h */,
-				500B203F1C4B43930002B53F /* ZahnradBackend.m */,
-				500B20231C4B41870002B53F /* main.m */,
-				504DFDEA1C4EA2CD00D3714A /* zahnrad.h */,
-				500B20411C4B43A30002B53F /* zahnrad.c */,
-				500B202A1C4B41880002B53F /* Info.plist */,
-			);
-			path = Mac_GL;
-			sourceTree = "<group>";
-		};
-		500B20431C4B43BC0002B53F /* font */ = {
-			isa = PBXGroup;
-			children = (
-				500B20441C4B43BC0002B53F /* DroidSans.ttf */,
-				500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */,
-				500B20461C4B43BC0002B53F /* Roboto-Light.ttf */,
-				500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */,
-			);
-			name = font;
-			path = ../../font;
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		500B201B1C4B41870002B53F /* Mac_GL */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 500B202D1C4B41880002B53F /* Build configuration list for PBXNativeTarget "Mac_GL" */;
-			buildPhases = (
-				500B20181C4B41870002B53F /* Sources */,
-				500B20191C4B41870002B53F /* Frameworks */,
-				500B201A1C4B41870002B53F /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = Mac_GL;
-			productName = Mac_GL;
-			productReference = 500B201C1C4B41870002B53F /* Mac_GL.app */;
-			productType = "com.apple.product-type.application";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		500B20141C4B41870002B53F /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0720;
-				ORGANIZATIONNAME = richi;
-				TargetAttributes = {
-					500B201B1C4B41870002B53F = {
-						CreatedOnToolsVersion = 7.2;
-					};
-				};
-			};
-			buildConfigurationList = 500B20171C4B41870002B53F /* Build configuration list for PBXProject "Mac_GL" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = 500B20131C4B41870002B53F;
-			productRefGroup = 500B201D1C4B41870002B53F /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				500B201B1C4B41870002B53F /* Mac_GL */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		500B201A1C4B41870002B53F /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B20491C4B43BC0002B53F /* Roboto-Bold.ttf in Resources */,
-				500B20481C4B43BC0002B53F /* DroidSans.ttf in Resources */,
-				500B204B1C4B43BC0002B53F /* Roboto-Regular.ttf in Resources */,
-				500B204A1C4B43BC0002B53F /* Roboto-Light.ttf in Resources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		500B20181C4B41870002B53F /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B20241C4B41870002B53F /* main.m in Sources */,
-				500B20421C4B43A30002B53F /* zahnrad.c in Sources */,
-				500B20401C4B43930002B53F /* ZahnradBackend.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		500B202B1C4B41880002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				CODE_SIGN_IDENTITY = "-";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = dwarf;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.8;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = macosx;
-			};
-			name = Debug;
-		};
-		500B202C1C4B41880002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				CODE_SIGN_IDENTITY = "-";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.8;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = macosx;
-			};
-			name = Release;
-		};
-		500B202E1C4B41880002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				COMBINE_HIDPI_IMAGES = YES;
-				INFOPLIST_FILE = Mac_GL/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.Mac-GL";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Debug;
-		};
-		500B202F1C4B41880002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				COMBINE_HIDPI_IMAGES = YES;
-				INFOPLIST_FILE = Mac_GL/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.Mac-GL";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		500B20171C4B41870002B53F /* Build configuration list for PBXProject "Mac_GL" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B202B1C4B41880002B53F /* Debug */,
-				500B202C1C4B41880002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		500B202D1C4B41880002B53F /* Build configuration list for PBXNativeTarget "Mac_GL" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B202E1C4B41880002B53F /* Debug */,
-				500B202F1C4B41880002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 500B20141C4B41870002B53F /* Project object */;
-}

+ 0 - 7
demo/apple/Mac_GL.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:Mac_GL.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 32
demo/apple/Mac_GL/Info.plist

@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIconFile</key>
-	<string></string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSMinimumSystemVersion</key>
-	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
-	<key>NSHumanReadableCopyright</key>
-	<string>Copyright © 2016 richi. All rights reserved.</string>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
-</dict>
-</plist>

+ 0 - 400
demo/apple/Mac_GL/main.m

@@ -1,400 +0,0 @@
-/*
- Copyright (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-
-#import "ZahnradBackend.h"
-
-
-@interface ZahnradView : NSOpenGLView
-
-@end
-
-
-@implementation ZahnradView
-{
-    ZahnradBackend* zr;
-
-    NSTrackingArea* currentTrackingArea;
-    CVDisplayLinkRef displayLink;
-}
-
-
-#pragma mark - Setup -
-
-
-- (instancetype) initWithFrame: (NSRect) frameRect
-{
-    NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = {
-        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
-        NSOpenGLPFAColorSize, 24,
-        NSOpenGLPFAAlphaSize, 8,
-        NSOpenGLPFADoubleBuffer,
-        NSOpenGLPFAAccelerated,
-        NSOpenGLPFANoRecovery,
-        0
-    };
-    
-    NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: pixelFormatAttributes];
-    assert(self = [super initWithFrame: frameRect pixelFormat: pixelFormat]);
-    
-    [self updateTrackingArea];
-    
-    [[self openGLContext] makeCurrentContext];
-    zr = [[ZahnradBackend alloc] initWithView: self];
-    
-    return self;
-}
-
-
-#if !SIMULATE_TOUCH
-
-
-static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
-{
-    return [(__bridge ZahnradView*) displayLinkContext drawFrameForTime: outputTime];
-}
-
-
-- (void) prepareOpenGL
-{
-    // Synchronize buffer swaps with vertical refresh rate
-    GLint swapInt = 1;
-    [[self openGLContext] setValues: &swapInt forParameter: NSOpenGLCPSwapInterval];
-    
-    // Create a display link capable of being used with all active displays
-    CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
-    
-    // Set the renderer output callback function
-    CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, (__bridge void* _Nullable)(self));
-    
-    // Set the display link for the current renderer
-    CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
-    CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
-    CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
-    
-    // Activate the display link
-    CVDisplayLinkStart(displayLink);
-}
-
-
-#endif
-
-
-- (void) glLocked: (dispatch_block_t) block
-{
-    CGLLockContext(self.openGLContext.CGLContextObj);
-    
-    @try
-    {
-        block();
-    }
-    @catch (NSException *exception)
-    {
-        NSLog(@"%@", exception);
-    }
-    @finally
-    {
-        CGLUnlockContext(self.openGLContext.CGLContextObj);
-    }
-}
-
-
-#pragma mark - Drawing -
-
-
-- (void) drawFrame
-{
-    glClearColor(0, 0, 0, 1);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    [zr updateFrame];
-    [zr drawFrameWithScale: 1.0 width: self.bounds.size.width height: self.bounds.size.height];
-
-    [[self openGLContext] flushBuffer];
-}
-
-
-- (CVReturn) drawFrameForTime: (const CVTimeStamp*) outputTime
-{
-    @autoreleasepool
-    {
-        [self glLocked: ^{
-            [[self openGLContext] makeCurrentContext];
-            [self drawFrame];
-        }];
-    }
-    
-    return kCVReturnSuccess;
-}
-
-
-- (void) drawRect: (NSRect) dirtyRect
-{
-    [self glLocked: ^{
-        [[self openGLContext] makeCurrentContext];
-        [super drawRect: dirtyRect];
-        [self drawFrame];
-    }];
-}
-
-
-#pragma mark - User Input -
-
-
-- (void) addEvent: (NSDictionary*) event
-{
-    [self glLocked: ^{
-        [zr addEvent: event];
-    }];
-
-#if SIMULATE_TOUCH
-    
-    [self setNeedsDisplay: YES];
-
-#endif
-}
-
-
-- (void) mouseMoved: (NSEvent*) theEvent
-{
-#if !SIMULATE_TOUCH
-    
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @1, @"pos" : NSStringFromPoint(location)}];
-
-#endif
-}
-
-
-- (void) mouseDragged: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @2, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) rightMouseDragged: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @3, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) otherMouseDragged: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @4, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) mouseDown: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @5, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) mouseUp: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @6, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) rightMouseDown: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @7, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) rightMouseUp: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @8, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) otherMouseDown: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @9, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) otherMouseUp: (NSEvent*) theEvent
-{
-    NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
-    [self addEvent: @{@"type" : @10, @"pos" : NSStringFromPoint(location)}];
-}
-
-
-- (void) scrollWheel: (NSEvent*) theEvent
-{
-    [self addEvent: @{@"type" : @11, @"deltaX" : @(theEvent.deltaX), @"deltaY" : @(theEvent.deltaY)}];
-}
-
-
-- (void) keyDown: (NSEvent*) theEvent
-{
-    NSString* str = theEvent.characters;
-    
-    if (str.length)
-        [self addEvent: @{@"type" : @12, @"txt" : str, @"mod" : @(theEvent.modifierFlags)}];
-}
-
-
-- (void) keyUp: (NSEvent*) theEvent
-{
-    NSString* str = theEvent.characters;
-    
-    if (str.length)
-        [self addEvent: @{@"type" : @13, @"txt" : str, @"mod" : @(theEvent.modifierFlags)}];
-}
-
-
-- (BOOL) acceptsFirstResponder
-{
-    return YES;
-}
-
-
-- (void) removeCurrentTrackingArea
-{
-    if (currentTrackingArea)
-    {
-        [self removeTrackingArea: currentTrackingArea];
-        currentTrackingArea = nil;
-    }
-}
-
-
-- (void) updateTrackingArea
-{
-    [self removeCurrentTrackingArea];
-
-#if !SIMULATE_TOUCH
-    
-    currentTrackingArea = [[NSTrackingArea alloc]
-                           initWithRect: self.bounds
-                           options: NSTrackingMouseMoved | NSTrackingActiveInActiveApp
-                           owner: self
-                           userInfo: nil];
-    
-    [self addTrackingArea: currentTrackingArea];
-    
-#endif
-}
-
-
-- (void) reshape
-{
-    [self updateTrackingArea];
-    NSRect bounds = [self bounds];
-    
-    [self glLocked: ^{
-        [[self openGLContext] makeCurrentContext];
-        glViewport((GLint)NSMinX(bounds), (GLint)NSMinY(bounds), (GLint)NSWidth(bounds), (GLint)NSHeight(bounds));
-    }];
-}
-
-
-- (void) update
-{
-    [self glLocked: ^{
-        [super update];
-    }];
-}
-
-
-@end
-
-
-#pragma mark - App Delegate -
-
-
-@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
-
-@property (strong) IBOutlet NSWindow* window;
-
-@end
-
-
-@implementation AppDelegate
-
-
-- (void) applicationDidFinishLaunching: (NSNotification*) aNotification
-{
-    NSString* appName = [[NSProcessInfo processInfo] processName];
-    
-    NSLog(@"Starting %@", appName);
-    
-    NSMenu* appMenu = [NSMenu new];
-    [appMenu addItem: [[NSMenuItem alloc] initWithTitle: [@"Quit " stringByAppendingString: appName]
-                                                 action: @selector(terminate:)
-                                          keyEquivalent: @"q"]];
-    NSMenuItem* appMenuItem = [NSMenuItem new];
-    [appMenuItem setSubmenu: appMenu];
-    NSMenu* menubar = [NSMenu new];
-    [menubar addItem: appMenuItem];
-    [NSApp setMainMenu: menubar];
-    
-    NSRect frame = NSMakeRect(0, 0, 800, 600);
-    
-    _window = [[NSWindow alloc] initWithContentRect: frame
-                                          styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
-                                            backing: NSBackingStoreBuffered
-                                              defer: NO];
-    
-    [_window setContentView: [[ZahnradView alloc] initWithFrame: frame]];
-    [_window setDelegate: self];
-    
-    [_window setTitle: appName];
-    [_window cascadeTopLeftFromPoint: NSMakePoint(20, 20)];
-    [_window makeKeyAndOrderFront: nil];
-}
-
-
-- (void) windowWillClose: (NSNotification*) notification
-{
-    [NSApp terminate: self];
-}
-
-
-@end
-
-
-int main()
-{
-    @autoreleasepool
-    {
-        [NSApplication sharedApplication];
-        [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
-        
-        AppDelegate* appDelegate = [AppDelegate new];
-        [NSApp setDelegate: appDelegate];
-        
-        [NSApp run];
-    }
-    
-    return EXIT_SUCCESS;
-}
-
-

+ 0 - 19
demo/apple/README.md

@@ -1,19 +0,0 @@
-Zahnrad for Mac OS X, iOS and tvOS
-==================================
-
-This is a bunch of experimental render backends for [Zahnrad](https://github.com/vurtun/zahnrad) a gorgeous immediate mode GUI toolkit.
-
-Included are native versions for Mac OS X, iOS and tvOS. The Mac version is using OpenGL 3.2. iOS and tvOS are running on OpenGL ES 3.2. 
-
-Versions utilising Metal are in the making. 
-
-How to use?
------------
-
-Open `ZahnradBackend.xcworkspace` with XCode and start your engines.
-
-
-License
--------
-
-[WTFPL](http://www.wtfpl.net)

+ 0 - 81
demo/apple/ZahnradBackend.h

@@ -1,81 +0,0 @@
-/*
- Copyright (c) 2016 Micha Mettke
- Macintosh / Objective-C adaptation (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-#import <Foundation/Foundation.h>
-
-#import "zahnrad.h"
-
-#define SIMULATE_TOUCH 0
-
-#if (TARGET_OS_IPHONE && (!TARGET_OS_TV)) || SIMULATE_TOUCH
-    #define ZR_REFRESH_ON_EVENT_ONLY 0
-    #define ZR_TOUCH_SCREEN 1
-#endif
-
-#if TARGET_OS_IPHONE
-    #import <UIKit/UIKit.h>
-    #import <GLKit/GLKit.h>
-    #import <OpenGLES/ES3/gl.h>
-    #import <OpenGLES/ES3/glext.h>
-    #define GLVIEW  GLKView
-#else
-    #import <Cocoa/Cocoa.h>
-    #import <OpenGL/OpenGL.h>
-    #import <OpenGL/gl.h>
-    #import <OpenGL/gl3.h>
-    #define GLVIEW  NSOpenGLView
-#endif
-
-
-@interface ZahnradBackend : NSObject
-
-
-@property (readonly) GLVIEW* view;
-
-- (instancetype) initWithView: (GLVIEW*) view;
-
-- (void) addEvent: (NSDictionary*) event;
-- (void) updateFrame;
-- (void) drawFrameWithScale: (CGFloat) scale width: (CGFloat) width height: (CGFloat) height;
-
-@end
-
-
-@interface ZahnradBackend (Adapter)
-
-
-- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
-                                     allocator: (struct zr_allocator*) alloc
-                                   defaultFont: (struct zr_user_font*) defFont;
-
-- (int) fillFrame;
-
-
-@end
-
-
-void zr_backend_show_keyboard(zr_hash hash, struct zr_rect bounds, struct zr_buffer* text);
-void zr_backend_hide_keyboard(void);
-
-int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id);
-
-
-

+ 0 - 767
demo/apple/ZahnradBackend.m

@@ -1,767 +0,0 @@
-/*
- Copyright (c) 2016 Micha Mettke
- Macintosh / Objective-C adaptation (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-#import "ZahnradBackend.h"
-
-
-#define MAX_VERTEX_MEMORY   (512 * 1024)
-#define MAX_ELEMENT_MEMORY  (128 * 1024)
-
-
-// This is the adapter for demo.c.
-// #else does provide a generic version to start
-// your own project.
-
-
-#if 1
-
-#if TARGET_OS_IPHONE
-
-#define zr_edit_string(_ct, _fl, _bu, _le, _ma, _fi) zr_touch_edit_string(_ct, _fl, _bu, _le, _ma, _fi, (zr_hash)__COUNTER__)
-
-#endif
-
-
-#define DEMO_DO_NOT_DRAW_IMAGES
-#include "../demo.c"
-
-@implementation ZahnradBackend (Adapter)
-
-static struct demo gui;
-
-
-- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
-                                     allocator: (struct zr_allocator*) alloc
-                                   defaultFont: (struct zr_user_font*) defFont
-{
-    memset(&gui, 0, sizeof(gui));
-    zr_buffer_init(cmds, alloc, 4096);
-    zr_init(&gui.ctx, alloc, defFont);
-    return &gui.ctx;
-}
-
-
-- (int) fillFrame;
-{
-    return run_demo(&gui);
-}
-
-
-@end
-
-
-#else
-
-
-#import "ZahnradBackend.h"
-
-
-@implementation ZahnradBackend (Adapter)
-
-static struct zr_context context;
-
-
-- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
-                                     allocator: (struct zr_allocator*) alloc
-                                   defaultFont: (struct zr_user_font*) defFont
-{
-    memset(&context, 0, sizeof(context));
-    
-    zr_buffer_init(cmds, alloc, 4096);
-    zr_init(&context, alloc, defFont);
-    
-    return &context;
-}
-
-
-- (int) fillFrame;
-{
-    return 1;
-}
-
-@end
-
-
-#endif
-
-
-@implementation ZahnradBackend
-{
-    struct zr_context* context;
-
-    struct zr_allocator alloc;
-    struct zr_user_font sysFnt;
-    struct zr_font font;
-    struct zr_draw_null_texture nullTexture;
-
-    struct zr_buffer cmds;
-    NSMutableArray* bufferedCommands;
-    NSMutableArray* events;
-
-    struct
-    {
-        GLuint vbo, vao, ebo;
-        GLuint program;
-        GLuint vertexShader;
-        GLuint fragmentShader;
-        GLint attributePosition;
-        GLint attributeUV;
-        GLint attributeColor;
-        GLint uniformTexture;
-        GLint uniformProjection;
-        GLuint fontTexture;
-    } device;
-}
-
-
-static void* mem_alloc(zr_handle unused, size_t size)
-{
-    return calloc(1, size);
-}
-
-
-static void mem_free(zr_handle unused, void* ptr)
-{
-    free(ptr);
-}
-
-
-#pragma mark - Setup -
-
-
-- (instancetype) initWithView: (GLVIEW*) view;
-{
-    if (!(self = [super init])) return self;
-
-    _view = view;
-
-    events = [NSMutableArray new];
-    bufferedCommands = [NSMutableArray new];
-
-    [self setupGL];
-
-    NSURL* fontURL = [[NSBundle mainBundle] URLForResource: @"DroidSans" withExtension: @"ttf"];
-    assert(fontURL != nil);
-
-    alloc.userdata.ptr = NULL;
-    alloc.alloc = mem_alloc;
-    alloc.free = mem_free;
-
-    sysFnt = [self fontFromUrl: fontURL height: 14 range: zr_font_default_glyph_ranges()];
-
-    context = [self createContextWithBuffer: &cmds allocator: &alloc defaultFont: &sysFnt];
-    [self fillFrame];
-
-    return self;
-}
-
-
-- (void) setupGL
-{
-    GLint status;
-
-    static const GLchar* vss =
-#if TARGET_OS_IPHONE
-    "#version 300 es\n"
-#else
-    "#version 150\n"
-#endif
-    "uniform mat4 ProjMtx;\n"
-    "in vec2 Position;\n"
-    "in vec2 TexCoord;\n"
-    "in vec4 Color;\n"
-    "out vec2 Frag_UV;\n"
-    "out vec4 Frag_Color;\n"
-    "void main() {\n"
-    "   Frag_UV = TexCoord;\n"
-    "   Frag_Color = Color;\n"
-    "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
-    "}\n";
-
-    static const GLchar* fss =
-#if TARGET_OS_IPHONE
-    "#version 300 es\n"
-#else
-    "#version 150\n"
-#endif
-    "precision mediump float;\n"
-    "uniform sampler2D Texture;\n"
-    "in vec2 Frag_UV;\n"
-    "in vec4 Frag_Color;\n"
-    "out vec4 Out_Color;\n"
-    "void main(){\n"
-    "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
-    "}\n";
-
-    device.program = glCreateProgram();
-    device.vertexShader = glCreateShader(GL_VERTEX_SHADER);
-    glShaderSource(device.vertexShader, 1, &vss, 0);
-    glCompileShader(device.vertexShader);
-
-#if defined(DEBUG)
-    GLint logLength;
-    glGetShaderiv(device.vertexShader, GL_INFO_LOG_LENGTH, &logLength);
-    if (logLength > 0)
-    {
-        GLchar* log = (GLchar*)malloc(logLength);
-        glGetShaderInfoLog(device.vertexShader, logLength, &logLength, log);
-        NSLog(@"Shader compile log:\n%s", log);
-        free(log);
-    }
-#endif
-
-    glGetShaderiv(device.vertexShader, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    device.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(device.fragmentShader, 1, &fss, 0);
-    glCompileShader(device.fragmentShader);
-
-#if defined(DEBUG)
-    glGetShaderiv(device.fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
-    if (logLength > 0)
-    {
-        GLchar* log = (GLchar*)malloc(logLength);
-        glGetShaderInfoLog(device.fragmentShader, logLength, &logLength, log);
-        NSLog(@"Shader compile log:\n%s", log);
-        free(log);
-    }
-#endif
-
-    glGetShaderiv(device.fragmentShader, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    glAttachShader(device.program, device.vertexShader);
-    glAttachShader(device.program, device.fragmentShader);
-    glLinkProgram(device.program);
-
-#if defined(DEBUG)
-    glGetProgramiv(device.program, GL_INFO_LOG_LENGTH, &logLength);
-    if (logLength > 0)
-    {
-        GLchar* log = (GLchar*)malloc(logLength);
-        glGetProgramInfoLog(device.program, logLength, &logLength, log);
-        NSLog(@"Program link log:\n%s", log);
-        free(log);
-    }
-#endif
-
-    glGetProgramiv(device.program, GL_LINK_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    device.uniformTexture = glGetUniformLocation(device.program, "Texture");
-    device.uniformProjection = glGetUniformLocation(device.program, "ProjMtx");
-    device.attributePosition = glGetAttribLocation(device.program, "Position");
-    device.attributeUV = glGetAttribLocation(device.program, "TexCoord");
-    device.attributeColor = glGetAttribLocation(device.program, "Color");
-
-    // buffer setup
-    GLsizei vs = sizeof(struct zr_draw_vertex);
-    size_t vp = offsetof(struct zr_draw_vertex, position);
-    size_t vt = offsetof(struct zr_draw_vertex, uv);
-    size_t vc = offsetof(struct zr_draw_vertex, col);
-
-    // allocate vertex and element buffer
-    glGenBuffers(1, &device.vbo);
-    glGenBuffers(1, &device.ebo);
-    glGenVertexArrays(1, &device.vao);
-
-    glBindVertexArray(device.vao);
-    glBindBuffer(GL_ARRAY_BUFFER, device.vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, device.ebo);
-
-    glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
-
-    glEnableVertexAttribArray((GLuint)device.attributePosition);
-    glEnableVertexAttribArray((GLuint)device.attributeUV);
-    glEnableVertexAttribArray((GLuint)device.attributeColor);
-
-    glVertexAttribPointer((GLuint)device.attributePosition, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
-    glVertexAttribPointer((GLuint)device.attributeUV, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
-    glVertexAttribPointer((GLuint)device.attributeColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-}
-
-
-- (struct zr_user_font) fontFromUrl: (NSURL*) url height: (unsigned) fontHeight range: (const zr_rune*) range
-{
-    struct zr_baked_font baked_font;
-    struct zr_recti custom;
-
-    memset(&baked_font, 0, sizeof(baked_font));
-    memset(&custom, 0, sizeof(custom));
-
-    // bake and upload font texture
-    NSData* ttfData = [NSData dataWithContentsOfURL: url];
-    assert(ttfData != nil);
-
-    // setup font configuration
-    struct zr_font_config config;
-    memset(&config, 0, sizeof(config));
-    config.ttf_blob = (void*)ttfData.bytes;
-    config.font = &baked_font;
-    config.coord_type = ZR_COORD_UV;
-    config.range = range;
-    config.pixel_snap = zr_false;
-    config.size = (float)fontHeight;
-    config.spacing = zr_vec2(0, 0);
-    config.oversample_h = 1;
-    config.oversample_v = 1;
-    config.merge_mode = 0;
-
-    // query needed amount of memory for the font baking process
-    int glyph_count;
-    size_t tmp_size;
-    zr_font_bake_memory(&tmp_size, &glyph_count, &config, 1);
-    struct zr_font_glyph* glyphes = (struct zr_font_glyph*)calloc(sizeof(struct zr_font_glyph), (size_t)glyph_count);
-    void* tmp = calloc(1, tmp_size);
-
-    // pack all glyphes and return needed image width, height and memory size
-    int img_width, img_height;
-    size_t img_size;
-    custom.w = 2; custom.h = 2;
-    assert(zr_font_bake_pack(&img_size, &img_width, &img_height, &custom, tmp, tmp_size, &config, 1));
-
-    // bake all glyphes and custom white pixel into image
-    const char* custom_data = "....";
-    void* img = calloc(1, img_size);
-    zr_font_bake(img, img_width, img_height, tmp, tmp_size, glyphes, glyph_count, &config, 1);
-    zr_font_bake_custom_data(img, img_width, img_height, custom, custom_data, 2, 2, '.', 'X');
-
-    // convert alpha8 image into rgba8 image
-    void* img_rgba = calloc(4, (size_t)(img_height * img_width));
-    zr_font_bake_convert(img_rgba, img_width, img_height, img);
-    free(img);
-    img = img_rgba;
-
-    // upload baked font image
-    glGenTextures(1, &device.fontTexture);
-    glBindTexture(GL_TEXTURE_2D, device.fontTexture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)img_width, (GLsizei)img_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
-
-    free(tmp);
-    free(img);
-
-    // default white pixel in a texture which is needed to draw primitives
-    nullTexture.texture.id = (int)device.fontTexture;
-    nullTexture.uv = zr_vec2((custom.x + 0.5f) / (float)img_width, (custom.y + 0.5f) / (float)img_height);
-
-    /* setup font with glyphes. IMPORTANT: the font only references the glyphes
-     this was done to have the possibility to have multible fonts with one
-     total glyph array. Not quite sure if it is a good thing since the
-     glyphes have to be freed as well.
-     */
-    zr_font_init(&font, (float)fontHeight, '?', glyphes, &baked_font, nullTexture.texture);
-
-    return &font.handle;
-}
-
-
-#pragma mark - Drawing -
-
-
-- (void) drawFrameWithScale: (CGFloat) scale width: (CGFloat) width height: (CGFloat) height
-{
-    // save opengl state
-    GLint last_prog, last_tex;
-    GLint last_ebo, last_vbo, last_vao;
-    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
-    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
-    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
-    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
-
-    // setup global state
-    glEnable(GL_BLEND);
-    glBlendEquation(GL_FUNC_ADD);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-    glEnable(GL_SCISSOR_TEST);
-    glActiveTexture(GL_TEXTURE0);
-
-    // setup program
-    GLfloat ortho[4][4] = {
-        {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},
-    };
-    ortho[0][0] /= width;
-    ortho[1][1] /= height;
-    glUseProgram(device.program);
-    glUniform1i(device.uniformTexture, 0);
-    glUniformMatrix4fv(device.uniformProjection, 1, GL_FALSE, &ortho[0][0]);
-
-    // activate vertex and element buffer
-    glBindVertexArray(device.vao);
-    glBindBuffer(GL_ARRAY_BUFFER, device.vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, device.ebo);
-
-    // if draw commands have been buffered we will draw only those
-    if (bufferedCommands.count)
-    {
-        const struct zr_draw_command* cmd;
-        const zr_draw_index* offset = NULL;
-
-        // iterate over and execute each draw command
-        for (NSData* data in bufferedCommands)
-        {
-            cmd = data.bytes;
-            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-            glScissor((GLint)(cmd->clip_rect.x * scale),
-                      (GLint)((height - (cmd->clip_rect.y + cmd->clip_rect.h)) * scale),
-                      (GLint)(cmd->clip_rect.w * scale),
-                      (GLint)(cmd->clip_rect.h * scale));
-            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-            offset += cmd->elem_count;
-        }
-    }
-    else
-    {
-        // load draw vertices & elements  into vertex + element buffer
-        void* vertices = glMapBufferRange(GL_ARRAY_BUFFER, 0, MAX_VERTEX_MEMORY, GL_MAP_WRITE_BIT);
-        void* elements = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, MAX_ELEMENT_MEMORY, GL_MAP_WRITE_BIT);
-        //
-        // fill converting configuration
-        struct zr_convert_config config;
-        memset(&config, 0, sizeof(config));
-        config.global_alpha = 1.0f;
-        config.shape_AA = ZR_ANTI_ALIASING_ON;
-        config.line_AA = ZR_ANTI_ALIASING_ON;
-        config.circle_segment_count = 22;
-        config.curve_segment_count = 22;
-        config.arc_segment_count = 22;
-        config.null = nullTexture;
-        //
-        // setup buffers to load vertices and elements
-        struct zr_buffer vbuf, ebuf;
-        zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
-        zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
-        zr_convert(context, &cmds, &vbuf, &ebuf, &config);
-
-        glUnmapBuffer(GL_ARRAY_BUFFER);
-        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-        //
-        // convert from command queue into draw list and draw to screen
-        const struct zr_draw_command* cmd;
-        const zr_draw_index* offset = NULL;
-        [bufferedCommands removeAllObjects];
-        // iterate over and execute each draw command
-        zr_draw_foreach(cmd, context, &cmds)
-        {
-            if (cmd->elem_count > 0)
-            {
-#if ZR_REFRESH_ON_EVENT_ONLY
-                [bufferedCommands addObject: [NSData dataWithBytes: cmd length: sizeof(struct zr_draw_command)]];
-#endif
-                glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-                glScissor((GLint)(cmd->clip_rect.x * scale),
-                          (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale),
-                          (GLint)(cmd->clip_rect.w * scale),
-                          (GLint)(cmd->clip_rect.h * scale));
-                glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-                offset += cmd->elem_count;
-            }
-        }
-        zr_clear(context);
-    }
-    // restore old state
-    glUseProgram((GLuint)last_prog);
-    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
-    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
-    glBindVertexArray((GLuint)last_vao);
-    glDisable(GL_SCISSOR_TEST);
-}
-
-
-#pragma mark - Events -
-
-
-- (void) updateFrame
-{
-
-#if ZR_REFRESH_ON_EVENT_ONLY
-    if (events.count)
-#endif
-    {
-        [self handleEvents];
-        [self fillFrame];
-    }
-}
-
-
-- (void) handleEvents
-{
-    NSArray* currentEvents = events.copy;
-    [events removeAllObjects];
-
-    zr_input_begin(context);
-
-    for (NSDictionary* event in currentEvents)
-    {
-#if TARGET_OS_IPHONE
-        CGPoint location = CGPointFromString(event[@"pos"]);
-#else
-        NSPoint location = NSPointFromString(event[@"pos"]);
-        location.y = (int)(self.view.bounds.size.height - location.y);
-#endif
-
-        int x = (int)location.x;
-        int y = (int)location.y;
-        int type = [event[@"type"] intValue];
-
-        switch (type)
-        {
-
-#if ZR_REFRESH_ON_EVENT_ONLY || ZR_TOUCH_SCREEN
-
-            case 2: case 3: case 4:
-                zr_input_motion(context, x, y);
-                break;
-            case 5:
-                zr_input_motion(context, x, y);
-                zr_input_end(context);
-                zr_input_begin(context);
-                zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_true);
-                break;
-            case 6:
-                zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_false);
-                zr_input_end(context);
-                [self fillFrame];
-                zr_clear(context);
-                zr_input_begin(context);
-                zr_input_motion(context, INT_MAX, INT_MAX);
-                break;
-
-#else
-
-            case 1: case 2: case 3: case 4:
-                zr_input_motion(context, x, y);
-                break;
-            case 5:
-                zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_true);
-                break;
-            case 6:
-                zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_false);
-                break;
-            case 7:
-                zr_input_button(context, ZR_BUTTON_RIGHT, x, y, zr_true);
-                break;
-            case 8:
-                zr_input_button(context, ZR_BUTTON_RIGHT, x, y, zr_false);
-                break;
-            case 9:
-                zr_input_button(context, ZR_BUTTON_MIDDLE, x, y, zr_true);
-                break;
-            case 10:
-                zr_input_button(context, ZR_BUTTON_MIDDLE, x, y, zr_false);
-                break;
-            case 11:
-                zr_input_scroll(context, -[event[@"deltaY"] floatValue]);
-                break;
-#endif
-
-            case 12:
-            case 13:
-            {
-                int down = type == 12 ? zr_true : zr_false;
-                NSString* str = event[@"txt"];
-                NSData* data = [str dataUsingEncoding: NSUTF32LittleEndianStringEncoding];
-                const uint32_t* c = data.bytes;
-                NSInteger n = data.length / sizeof(uint32_t);
-
-#if TARGET_OS_IPHONE
-
-                if (down)
-                {
-                    if (n && *c == '\b')
-                    {
-                        zr_input_key(context, ZR_KEY_BACKSPACE, zr_true);
-                        zr_input_end(context);
-                        [self fillFrame];
-                        zr_clear(context);
-                        zr_input_begin(context);
-                        zr_input_key(context, ZR_KEY_BACKSPACE, zr_false);
-                    }
-                    else
-                    {
-                        for (NSInteger i = 0; i < n; i += 1, c += 1)
-                            zr_input_unicode(context, *c);
-                    }
-                }
-
-#else
-
-                for (NSInteger i = 0; i < n; i += 1, c += 1)
-                {
-                    if (*c == 127 || *c < ' ' || *c >= NSUpArrowFunctionKey)
-                    {
-                        switch (*c)
-                        {
-                            case NSLeftArrowFunctionKey:
-                                zr_input_key(context, ZR_KEY_LEFT, down);
-                                break;
-                            case NSRightArrowFunctionKey:
-                                zr_input_key(context, ZR_KEY_RIGHT, down);
-                                break;
-                            case 3:
-                                zr_input_key(context, ZR_KEY_COPY, down);
-                                break;
-                            case 22:
-                                zr_input_key(context, ZR_KEY_PASTE, down);
-                                break;
-                            case 24:
-                                zr_input_key(context, ZR_KEY_CUT, down);
-                                break;
-                            case 9:
-                                zr_input_key(context, ZR_KEY_TAB, down);
-                                break;
-                            case 13:
-                                zr_input_key(context, ZR_KEY_ENTER, down);
-                                break;
-                            case 127:
-                                zr_input_key(context, ZR_KEY_BACKSPACE, down);
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    else if (down)
-                    {
-                        zr_input_unicode(context, *c);
-                    }
-                }
-#endif
-            }
-            break;
-
-            default:
-                break;
-        }
-    }
-
-    zr_input_end(context);
-}
-
-
-- (void) addEvent: (NSDictionary*) event
-{
-    [bufferedCommands removeAllObjects];
-    [events addObject: event];
-}
-
-
-@end
-
-
-@protocol ZahnradKeyboardDelegate <NSObject>
-
-- (void) showKeyboard: (NSDictionary*) info;
-- (void) hideKeyboard;
-
-@end
-
-
-#undef zr_edit_string
-
-
-#if TARGET_OS_IPHONE
-
-
-void zr_backend_show_keyboard(zr_hash zrHash, struct zr_rect zrBounds, struct zr_buffer* zrText)
-{
-    CGRect frame = CGRectMake(zrBounds.x, zrBounds.y, zrBounds.w, zrBounds.h);
-    id ad = [[UIApplication sharedApplication] delegate];
-    if ([ad respondsToSelector: @selector(showKeyboard:)])
-    {
-        char str[zrText->allocated + 1];
-        strncpy(str, zrText->memory.ptr, zrText->allocated);
-        str[zrText->allocated] = 0;
-        NSString* text = [NSString stringWithCString: str encoding: NSUTF8StringEncoding];
-        [ad performSelector: @selector(showKeyboard:) withObject: @{@"hash" : @(zrHash), @"text" : text, @"frame" : NSStringFromCGRect(frame)}];
-    }
-}
-
-
-void zr_backend_hide_keyboard(void)
-{
-    id ad = [[UIApplication sharedApplication] delegate];
-    if ([ad respondsToSelector: @selector(hideKeyboard)])
-        [ad performSelector: @selector(hideKeyboard)];
-}
-
-
-int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id)
-{
-    zr_flags state;
-    struct zr_rect bounds;
-
-    zr_layout_peek(&bounds, ctx);
-    state = zr_edit_string(ctx, flags, text, len, max, filter);
-    if (state & ZR_EDIT_ACTIVATED)
-    {
-        struct zr_buffer buffer;
-        zr_buffer_init_fixed(&buffer, text, max);
-        buffer.allocated = *len;
-
-        zr_backend_show_keyboard((zr_hash)unique_id, bounds, &buffer);
-    }
-    else if (state & ZR_EDIT_DEACTIVATED)
-    {
-        zr_backend_hide_keyboard();
-    }
-
-    return state;
-}
-
-
-#else
-
-
-void zr_backend_show_keyboard(zr_hash zrHash, struct zr_rect zrBounds, struct zr_buffer* zrText)
-{
-}
-
-
-void zr_backend_hide_keyboard(void)
-{
-}
-
-
-int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id)
-{
-    return  zr_edit_string(ctx, flags, text, len, max, filter);
-}
-
-
-#endif
-
-
-

+ 0 - 16
demo/apple/ZahnradBackend.xcworkspace/contents.xcworkspacedata

@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "group:Mac_GL.xcodeproj">
-   </FileRef>
-   <FileRef
-      location = "group:iOS_GL_ES.xcodeproj">
-   </FileRef>
-   <FileRef
-      location = "group:iOS_CoreGraphics.xcodeproj">
-   </FileRef>
-   <FileRef
-      location = "group:tvOS_GL_ES.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 275
demo/apple/iOS_CoreGraphics.xcodeproj/project.pbxproj

@@ -1,275 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		50F9C54A1C5FE56C009533F4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F9C5491C5FE56C009533F4 /* main.m */; };
-		50F9C5611C5FE7BD009533F4 /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 50F9C55F1C5FE7BD009533F4 /* zahnrad.c */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS_CoreGraphics.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		50F9C5491C5FE56C009533F4 /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
-		50F9C5591C5FE56C009533F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		50F9C55F1C5FE7BD009533F4 /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; };
-		50F9C5601C5FE7BD009533F4 /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
-		50F9C5621C5FE7D9009533F4 /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		50F9C5421C5FE56C009533F4 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		50F9C53C1C5FE56C009533F4 = {
-			isa = PBXGroup;
-			children = (
-				50F9C5471C5FE56C009533F4 /* iOS_CoreGraphics */,
-				50F9C5461C5FE56C009533F4 /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		50F9C5461C5FE56C009533F4 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		50F9C5471C5FE56C009533F4 /* iOS_CoreGraphics */ = {
-			isa = PBXGroup;
-			children = (
-				50F9C5621C5FE7D9009533F4 /* demo.c */,
-				50F9C55F1C5FE7BD009533F4 /* zahnrad.c */,
-				50F9C5601C5FE7BD009533F4 /* zahnrad.h */,
-				50F9C5491C5FE56C009533F4 /* main.m */,
-				50F9C5591C5FE56C009533F4 /* Info.plist */,
-				50F9C5481C5FE56C009533F4 /* Supporting Files */,
-			);
-			path = iOS_CoreGraphics;
-			sourceTree = "<group>";
-		};
-		50F9C5481C5FE56C009533F4 /* Supporting Files */ = {
-			isa = PBXGroup;
-			children = (
-			);
-			name = "Supporting Files";
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		50F9C5441C5FE56C009533F4 /* iOS_CoreGraphics */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 50F9C55C1C5FE56C009533F4 /* Build configuration list for PBXNativeTarget "iOS_CoreGraphics" */;
-			buildPhases = (
-				50F9C5411C5FE56C009533F4 /* Sources */,
-				50F9C5421C5FE56C009533F4 /* Frameworks */,
-				50F9C5431C5FE56C009533F4 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = iOS_CoreGraphics;
-			productName = iOS_CoreGraphics;
-			productReference = 50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */;
-			productType = "com.apple.product-type.application";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		50F9C53D1C5FE56C009533F4 /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0720;
-				ORGANIZATIONNAME = richi;
-				TargetAttributes = {
-					50F9C5441C5FE56C009533F4 = {
-						CreatedOnToolsVersion = 7.2;
-					};
-				};
-			};
-			buildConfigurationList = 50F9C5401C5FE56C009533F4 /* Build configuration list for PBXProject "iOS_CoreGraphics" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = 50F9C53C1C5FE56C009533F4;
-			productRefGroup = 50F9C5461C5FE56C009533F4 /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				50F9C5441C5FE56C009533F4 /* iOS_CoreGraphics */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		50F9C5431C5FE56C009533F4 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		50F9C5411C5FE56C009533F4 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				50F9C5611C5FE7BD009533F4 /* zahnrad.c in Sources */,
-				50F9C54A1C5FE56C009533F4 /* main.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		50F9C55A1C5FE56C009533F4 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = dwarf;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
-			};
-			name = Debug;
-		};
-		50F9C55B1C5FE56C009533F4 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
-				VALIDATE_PRODUCT = YES;
-			};
-			name = Release;
-		};
-		50F9C55D1C5FE56C009533F4 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets";
-				INFOPLIST_FILE = iOS_CoreGraphics/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-CoreGraphics";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Debug;
-		};
-		50F9C55E1C5FE56C009533F4 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets";
-				INFOPLIST_FILE = iOS_CoreGraphics/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-CoreGraphics";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		50F9C5401C5FE56C009533F4 /* Build configuration list for PBXProject "iOS_CoreGraphics" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				50F9C55A1C5FE56C009533F4 /* Debug */,
-				50F9C55B1C5FE56C009533F4 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		50F9C55C1C5FE56C009533F4 /* Build configuration list for PBXNativeTarget "iOS_CoreGraphics" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				50F9C55D1C5FE56C009533F4 /* Debug */,
-				50F9C55E1C5FE56C009533F4 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 50F9C53D1C5FE56C009533F4 /* Project object */;
-}

+ 0 - 7
demo/apple/iOS_CoreGraphics.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:iOS_CoreGraphics.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 50
demo/apple/iOS_CoreGraphics/Info.plist

@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIcons</key>
-	<dict/>
-	<key>CFBundleIcons~ipad</key>
-	<dict/>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UIStatusBarHidden</key>
-	<true/>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-	</array>
-	<key>UISupportedInterfaceOrientations~ipad</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
-</plist>

+ 0 - 341
demo/apple/iOS_CoreGraphics/main.m

@@ -1,341 +0,0 @@
-/*
- Copyright (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-
-#import <UIKit/UIKit.h>
-
-#define DEMO_DO_NOT_DRAW_IMAGES
-#include "zahnrad.h"
-#include "../../demo.c"
-
-
-static void* mem_alloc(zr_handle unused, size_t size)
-{
-    return calloc(1, size);
-}
-
-
-static void mem_free(zr_handle unused, void* ptr)
-{
-    free(ptr);
-}
-
-
-NSString* stringFromZR(const char* text, zr_size len)
-{
-    char cstr[len + 1];
-    strncpy(cstr, text, len);
-    cstr[len] = 0;
-    return [NSString stringWithUTF8String: cstr];
-}
-
-
-static zr_size fontTextWidth(zr_handle handle, float height, const char* text, zr_size len)
-{
-    UIFont* font = (__bridge UIFont*) handle.ptr;
-    NSString* aString = stringFromZR(text, len);
-    NSDictionary* attributes = @{ NSFontAttributeName: font};
-    CGSize stringSize = [aString sizeWithAttributes: attributes];
-    
-    return ceil(stringSize.width);
-}
-
-
-#pragma mark - ZRView -
-
-
-@interface ZRView : UIView
-{
-    UIFont* font;
-    struct zr_user_font usrfnt;
-    struct zr_allocator alloc;
-
-    struct demo gui;
-}
-
-@end
-
-
-@implementation ZRView
-
-
-- (instancetype) initWithFrame: (CGRect) frame
-{
-    if (!(self = [super initWithFrame: frame]))
-        return self;
-    
-    alloc.userdata.ptr = NULL;
-    alloc.alloc = mem_alloc;
-    alloc.free = mem_free;
-    
-    font = [UIFont systemFontOfSize: 11];
-    font = [UIFont fontWithName: @"Menlo-Regular" size: 11];
-    
-    NSDictionary* attributes = @{NSFontAttributeName: font};
-    CGSize stringSize = [@"W" sizeWithAttributes: attributes];
-    
-    memset(&usrfnt, 0, sizeof(usrfnt));
-    usrfnt.height = round(stringSize.height);
-    usrfnt.width = fontTextWidth;
-    usrfnt.userdata.ptr = (__bridge void*)(font);
-    
-    zr_init(&gui.ctx, &alloc, &usrfnt);
-    zr_clear(&gui.ctx);
-    run_demo(&gui);
-    
-    return self;
-}
-
-
-#define setColor(_c) \
-CGContextSetRGBStrokeColor(context, _c->color.r / 255.0, _c->color.g / 255.0, _c->color.b / 255.0, _c->color.a / 255.0); \
-CGContextSetRGBFillColor(context, _c->color.r / 255.0, _c->color.g / 255.0, _c->color.b / 255.0, _c->color.a / 255.0);
-
-
-- (void) drawRect: (CGRect) rect
-{
-    CGContextRef context = UIGraphicsGetCurrentContext();
-    UIGraphicsPushContext(context);
-    
-    UIColor* color = [UIColor blackColor];
-    CGContextSetFillColorWithColor(context, color.CGColor);
-    CGContextFillRect(context, rect);
-    
-    const struct zr_command* cmd;
-    
-    CGContextSaveGState(context);
-    
-    zr_foreach(cmd, &gui.ctx)
-    {
-        switch (cmd->type)
-        {
-            case ZR_COMMAND_SCISSOR:
-            {
-                const struct zr_command_scissor* s = zr_command(scissor, cmd);
-                CGRect cr = CGRectMake(s->x, s->y, s->w, s->h);
-                CGContextRestoreGState(context);
-                CGContextSaveGState(context);
-                CGContextClipToRect(context, cr);
-            }   break;
-                
-            case ZR_COMMAND_LINE:
-            {
-                const struct zr_command_line* l = zr_command(line, cmd);
-                setColor(l);
-                CGContextBeginPath(context);
-                CGContextMoveToPoint(context, l->begin.x + .5, l->begin.y + .5);
-                CGContextAddLineToPoint(context, l->end.x + .5, l->end.y + .5);
-                CGContextStrokePath(context);
-            }   break;
-                
-            case ZR_COMMAND_RECT:
-            {
-                const struct zr_command_rect* r = zr_command(rect, cmd);
-                CGRect cr = CGRectMake(r->x, r->y, r->w, r->h);
-                setColor(r);
-                if (!r->rounding) CGContextFillRect(context, cr);
-                else
-                {
-                    CGMutablePathRef p = CGPathCreateMutable();
-                    CGPathAddRoundedRect(p, nil, cr, r->rounding, r->rounding);
-                    CGPathCloseSubpath(p);
-                    CGContextBeginPath(context);
-                    CGContextAddPath(context, p);
-                    CGContextDrawPath(context, kCGPathFill);
-                    CGPathRelease(p);
-                }
-            }   break;
-                
-            case ZR_COMMAND_CIRCLE:
-            {
-                const struct zr_command_circle* c = zr_command(circle, cmd);
-                CGRect cr = CGRectMake(c->x, c->y, c->w, c->h);
-                setColor(c);
-                CGContextFillEllipseInRect(context, cr);
-            }   break;
-                
-            case ZR_COMMAND_TRIANGLE:
-            {
-                const struct zr_command_triangle* t = zr_command(triangle, cmd);
-                setColor(t);
-                CGContextBeginPath(context);
-                CGContextMoveToPoint   (context, t->a.x, t->a.y);
-                CGContextAddLineToPoint(context, t->b.x, t->b.y);
-                CGContextAddLineToPoint(context, t->c.x, t->c.y);
-                CGContextClosePath(context);
-                CGContextFillPath(context);
-            }   break;
-                
-            case ZR_COMMAND_TEXT:
-            {
-                const struct zr_command_text* t = zr_command(text, cmd);
-                CGRect cr = CGRectMake(t->x, t->y, t->w, t->h);
-                CGContextSetRGBFillColor(context, t->background.r / 255.0, t->background.g / 255.0, t->background.b / 255.0, t->background.a / 255.0);
-                CGContextFillRect(context, cr);
-                NSString* aString = stringFromZR(t->string, t->length);
-                UIColor* fg = [UIColor colorWithRed: t->foreground.r / 255.0 green: t->foreground.g / 255.0 blue: t->foreground.b / 255.0 alpha: t->foreground.a / 255.0];
-                UIColor* bg = [UIColor colorWithRed: t->background.r / 255.0 green: t->background.g / 255.0 blue: t->background.b / 255.0 alpha: t->background.a / 255.0];
-                NSDictionary* attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: fg, NSBackgroundColorAttributeName: bg };
-                CGSize size = [aString sizeWithAttributes: attributes];
-                CGRect xr = CGRectMake(cr.origin.x, cr.origin.y + (cr.size.height - size.height) / 2.0, cr.size.width, size.height);
-                [aString drawInRect: xr withAttributes: attributes];
-            }   break;
-                
-            case ZR_COMMAND_CURVE:
-            case ZR_COMMAND_IMAGE:
-            case ZR_COMMAND_ARC:
-            case ZR_COMMAND_NOP:
-            default:
-                break;
-        }
-    }
-    
-    UIGraphicsPopContext();
-}
-
-
-- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self];
-    
-    zr_input_begin(&gui.ctx);
-    zr_input_motion(&gui.ctx, location.x, location.y);
-    zr_input_end(&gui.ctx);
-    
-    zr_clear(&gui.ctx);
-    zr_input_begin(&gui.ctx);
-    zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, location.x, location.y, zr_true);
-    zr_input_end(&gui.ctx);
-    
-    run_demo(&gui);
-    [self setNeedsDisplay];
-}
-
-
-- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self];
-    
-    zr_clear(&gui.ctx);
-    
-    zr_input_begin(&gui.ctx);
-    zr_input_motion(&gui.ctx, location.x, location.y);
-    zr_input_end(&gui.ctx);
-    
-    run_demo(&gui);
-    [self setNeedsDisplay];
-}
-
-
-- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self];
-    
-    zr_clear(&gui.ctx);
-    zr_input_begin(&gui.ctx);
-    zr_input_motion(&gui.ctx, location.x, location.y);
-    zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, location.x, location.y, zr_false);
-    zr_input_end(&gui.ctx);
-    run_demo(&gui);
-    
-    zr_clear(&gui.ctx);
-    zr_input_begin(&gui.ctx);
-    zr_input_motion(&gui.ctx, 0, 0);
-    zr_input_end(&gui.ctx);
-
-    run_demo(&gui);
-    [self setNeedsDisplay];
-}
-
-
-- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    [self touchesEnded: touches withEvent: event];
-}
-
-
-@end
-
-
-#pragma mark - ViewController -
-
-
-@interface ViewController : UIViewController
-
-@property (strong, nonatomic)  ZRView* zrView;
-
-@end
-
-
-@implementation ViewController
-
-
-- (void) viewDidLoad
-{
-    [super viewDidLoad];
-    
-    _zrView = [[ZRView alloc] initWithFrame: self.view.bounds];
-    [self.view addSubview: _zrView];
-}
-
-
-@end
-
-
-#pragma mark - App Delegate -
-
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow* window;
-@property (strong, nonatomic) ViewController* viewController;
-
-@end
-
-
-@implementation AppDelegate
-
-
-- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
-{
-    _window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
-    _viewController = [ViewController new];
-    _window.rootViewController = _viewController;
-    [_window makeKeyAndVisible];
-    
-    return YES;
-}
-
-
-@end
-
-
-int main(int argc, char* argv[])
-{
-    @autoreleasepool
-    {
-        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-    }
-}
-
-

+ 0 - 296
demo/apple/iOS_GL_ES.xcodeproj/project.pbxproj

@@ -1,296 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		500B20321C4B42B60002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20311C4B42B60002B53F /* ZahnradBackend.m */; };
-		500B20341C4B43010002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B20331C4B43010002B53F /* zahnrad.c */; };
-		500B203A1C4B43380002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20361C4B43380002B53F /* DroidSans.ttf */; };
-		500B203B1C4B43380002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20371C4B43380002B53F /* Roboto-Bold.ttf */; };
-		500B203C1C4B43380002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20381C4B43380002B53F /* Roboto-Light.ttf */; };
-		500B203D1C4B43380002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20391C4B43380002B53F /* Roboto-Regular.ttf */; };
-		504DFDF11C4EA36500D3714A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B1FF91C4B410F0002B53F /* main.m */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS_GL_ES.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		500B1FF91C4B410F0002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
-		500B200D1C4B410F0002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		500B20301C4B42B60002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B20311C4B42B60002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B20331C4B43010002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 4; };
-		500B20361C4B43380002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
-		500B20371C4B43380002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
-		500B20381C4B43380002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
-		500B20391C4B43380002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
-		504DFDEB1C4EA2EE00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
-		504DFDEF1C4EA36200D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		500B1FF21C4B410F0002B53F /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		500B1FEC1C4B410F0002B53F = {
-			isa = PBXGroup;
-			children = (
-				500B1FF71C4B410F0002B53F /* iOS_GL_ES */,
-				500B20351C4B43380002B53F /* font */,
-				500B1FF61C4B410F0002B53F /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		500B1FF61C4B410F0002B53F /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		500B1FF71C4B410F0002B53F /* iOS_GL_ES */ = {
-			isa = PBXGroup;
-			children = (
-				504DFDEF1C4EA36200D3714A /* demo.c */,
-				500B20301C4B42B60002B53F /* ZahnradBackend.h */,
-				500B20311C4B42B60002B53F /* ZahnradBackend.m */,
-				500B1FF91C4B410F0002B53F /* main.m */,
-				504DFDEB1C4EA2EE00D3714A /* zahnrad.h */,
-				500B20331C4B43010002B53F /* zahnrad.c */,
-				500B200D1C4B410F0002B53F /* Info.plist */,
-			);
-			path = iOS_GL_ES;
-			sourceTree = "<group>";
-		};
-		500B20351C4B43380002B53F /* font */ = {
-			isa = PBXGroup;
-			children = (
-				500B20361C4B43380002B53F /* DroidSans.ttf */,
-				500B20371C4B43380002B53F /* Roboto-Bold.ttf */,
-				500B20381C4B43380002B53F /* Roboto-Light.ttf */,
-				500B20391C4B43380002B53F /* Roboto-Regular.ttf */,
-			);
-			name = font;
-			path = ../../font;
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		500B1FF41C4B410F0002B53F /* iOS_GL_ES */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 500B20101C4B410F0002B53F /* Build configuration list for PBXNativeTarget "iOS_GL_ES" */;
-			buildPhases = (
-				500B1FF11C4B410F0002B53F /* Sources */,
-				500B1FF21C4B410F0002B53F /* Frameworks */,
-				500B1FF31C4B410F0002B53F /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = iOS_GL_ES;
-			productName = iOS_GL_ES;
-			productReference = 500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */;
-			productType = "com.apple.product-type.application";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		500B1FED1C4B410F0002B53F /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0720;
-				ORGANIZATIONNAME = richi;
-				TargetAttributes = {
-					500B1FF41C4B410F0002B53F = {
-						CreatedOnToolsVersion = 7.2;
-					};
-				};
-			};
-			buildConfigurationList = 500B1FF01C4B410F0002B53F /* Build configuration list for PBXProject "iOS_GL_ES" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = 500B1FEC1C4B410F0002B53F;
-			productRefGroup = 500B1FF61C4B410F0002B53F /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				500B1FF41C4B410F0002B53F /* iOS_GL_ES */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		500B1FF31C4B410F0002B53F /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B203B1C4B43380002B53F /* Roboto-Bold.ttf in Resources */,
-				500B203A1C4B43380002B53F /* DroidSans.ttf in Resources */,
-				500B203D1C4B43380002B53F /* Roboto-Regular.ttf in Resources */,
-				500B203C1C4B43380002B53F /* Roboto-Light.ttf in Resources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		500B1FF11C4B410F0002B53F /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B20341C4B43010002B53F /* zahnrad.c in Sources */,
-				504DFDF11C4EA36500D3714A /* main.m in Sources */,
-				500B20321C4B42B60002B53F /* ZahnradBackend.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		500B200E1C4B410F0002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
-			};
-			name = Debug;
-		};
-		500B200F1C4B410F0002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = iphoneos;
-				TARGETED_DEVICE_FAMILY = "1,2";
-				VALIDATE_PRODUCT = YES;
-			};
-			name = Release;
-		};
-		500B20111C4B410F0002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = iOS_GL_ES/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-GL-ES";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Debug;
-		};
-		500B20121C4B410F0002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = iOS_GL_ES/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-GL-ES";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		500B1FF01C4B410F0002B53F /* Build configuration list for PBXProject "iOS_GL_ES" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B200E1C4B410F0002B53F /* Debug */,
-				500B200F1C4B410F0002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		500B20101C4B410F0002B53F /* Build configuration list for PBXNativeTarget "iOS_GL_ES" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B20111C4B410F0002B53F /* Debug */,
-				500B20121C4B410F0002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 500B1FED1C4B410F0002B53F /* Project object */;
-}

+ 0 - 7
demo/apple/iOS_GL_ES.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:iOS_GL_ES.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 48
demo/apple/iOS_GL_ES/Info.plist

@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>UILaunchStoryboardName</key>
-	<string>LaunchScreen</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UIStatusBarHidden</key>
-	<true/>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-	</array>
-	<key>UISupportedInterfaceOrientations~ipad</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
-</plist>

+ 0 - 225
demo/apple/iOS_GL_ES/main.m

@@ -1,225 +0,0 @@
-/*
- Copyright (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-#import <UIKit/UIKit.h>
-#import <GLKit/GLKit.h>
-
-#import "ZahnradBackend.h"
-
-
-@interface GameViewController : GLKViewController <UIKeyInput>
-@end
-
-
-@implementation GameViewController
-{
-    BOOL keyboardAllowed;
-    NSUInteger keyboardHash;
-    
-    EAGLContext* context;
-    ZahnradBackend* zr;
-}
-
-
-- (void) viewDidLoad
-{
-    [super viewDidLoad];
-    
-    keyboardHash = -1;
-    
-    context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3];
-    assert(context != nil);
-    
-    ((GLKView*)self.view).context = context;
-    ((GLKView*)self.view).drawableDepthFormat = GLKViewDrawableDepthFormatNone;
-    
-    [EAGLContext setCurrentContext: context];
-    zr = [[ZahnradBackend alloc] initWithView: ((GLKView*)self.view)];
-}
-
-
-- (BOOL) prefersStatusBarHidden
-{
-    return YES;
-}
-
-
-- (void) update
-{
-    [zr updateFrame];
-}
-
-
-- (void) glkView: (GLKView*) view drawInRect: (CGRect) rect
-{
-    CGRect bounds = view.bounds;
-    CGFloat scale = view.window.screen.scale;
-    
-    glClearColor(0, 0, 0, 1);
-    glClear(GL_COLOR_BUFFER_BIT);
-    
-    [zr drawFrameWithScale: scale width: bounds.size.width height: bounds.size.height];
-}
-
-
-#pragma mark - User Input -
-
-
-- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self.view];
-    
-    [zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(location)}];
-}
-
-
-- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self.view];
-    
-    [zr addEvent: @{@"type" : @5, @"pos" : NSStringFromCGPoint(location)}];
-}
-
-
-- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    UITouch* touch = [[event allTouches] anyObject];
-    CGPoint location = [touch locationInView: self.view];
-    
-    [zr addEvent: @{@"type" : @6, @"pos" : NSStringFromCGPoint(location)}];
-}
-
-
-- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
-{
-    [self touchesEnded: touches withEvent: event];
-}
-
-
-- (void) insertText: (NSString*) text
-{
-    [zr addEvent: @{@"type" : @12, @"txt" : text, @"mod" : @0}];
-}
-
-
-- (void) deleteBackward
-{
-    [zr addEvent: @{@"type" : @12, @"txt" : @"\b", @"mod" : @0}];
-}
-
-
-- (BOOL) hasText
-{
-    return NO;
-}
-
-
-- (BOOL) canBecomeFirstResponder
-{
-    return keyboardAllowed;
-}
-
-
-- (BOOL) canResignFirstResponder
-{
-    return YES;
-}
-
-
-- (void) showKeyboard: (NSDictionary*) info
-{
-    NSUInteger hash = [info[@"hash"] unsignedIntegerValue];
-    
-    if (hash != keyboardHash)
-    {
-        keyboardHash = hash;
-        keyboardAllowed = YES;
-        if (!self.isFirstResponder)
-            [self becomeFirstResponder];
-    }
-}
-
-
-- (void) hideKeyboard
-{
-    keyboardHash = -1;
-    keyboardAllowed = NO;
-    [self resignFirstResponder];
-}
-
-
-@end
-
-
-#pragma mark - App Delegate -
-
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow* window;
-@property (strong, nonatomic) GameViewController* gameViewController;
-
-@end
-
-
-@implementation AppDelegate
-
-
-- (void) showKeyboard: (NSDictionary*) info
-{
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self.gameViewController showKeyboard: info];
-    });
-}
-
-
-- (void) hideKeyboard
-{
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self.gameViewController hideKeyboard];
-    });
-}
-
-
-- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
-{
-    _window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
-    _gameViewController = [GameViewController new];
-    _window.rootViewController = _gameViewController;
-    [_window makeKeyAndVisible];
-    
-    return YES;
-}
-
-
-@end
-
-
-int main(int argc, char* argv[])
-{
-    @autoreleasepool
-    {
-        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-    }
-}
-
-

+ 0 - 292
demo/apple/tvOS_GL_ES.xcodeproj/project.pbxproj

@@ -1,292 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		500B20661C4B4AB00002B53F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20651C4B4AB00002B53F /* main.m */; };
-		500B208A1C4B4D460002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20891C4B4D460002B53F /* ZahnradBackend.m */; };
-		500B208C1C4B4D580002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B208B1C4B4D580002B53F /* zahnrad.c */; };
-		500B20921C4B4D700002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B208E1C4B4D700002B53F /* DroidSans.ttf */; };
-		500B20931C4B4D700002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */; };
-		500B20941C4B4D700002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20901C4B4D700002B53F /* Roboto-Light.ttf */; };
-		500B20951C4B4D700002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20911C4B4D700002B53F /* Roboto-Regular.ttf */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tvOS_GL_ES.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		500B20651C4B4AB00002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
-		500B20741C4B4AB00002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		500B20881C4B4D460002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B20891C4B4D460002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
-		500B208B1C4B4D580002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 5; };
-		500B208E1C4B4D700002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
-		500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
-		500B20901C4B4D700002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
-		500B20911C4B4D700002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
-		504DFDEC1C4EA2FF00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
-		504DFDF21C4EA37700D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		500B205E1C4B4AB00002B53F /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		500B20581C4B4AB00002B53F = {
-			isa = PBXGroup;
-			children = (
-				500B20631C4B4AB00002B53F /* tvOS_GL_ES */,
-				500B208D1C4B4D700002B53F /* font */,
-				500B20621C4B4AB00002B53F /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		500B20621C4B4AB00002B53F /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		500B20631C4B4AB00002B53F /* tvOS_GL_ES */ = {
-			isa = PBXGroup;
-			children = (
-				504DFDF21C4EA37700D3714A /* demo.c */,
-				500B20881C4B4D460002B53F /* ZahnradBackend.h */,
-				500B20891C4B4D460002B53F /* ZahnradBackend.m */,
-				500B20651C4B4AB00002B53F /* main.m */,
-				504DFDEC1C4EA2FF00D3714A /* zahnrad.h */,
-				500B208B1C4B4D580002B53F /* zahnrad.c */,
-				500B20741C4B4AB00002B53F /* Info.plist */,
-			);
-			path = tvOS_GL_ES;
-			sourceTree = "<group>";
-		};
-		500B208D1C4B4D700002B53F /* font */ = {
-			isa = PBXGroup;
-			children = (
-				500B208E1C4B4D700002B53F /* DroidSans.ttf */,
-				500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */,
-				500B20901C4B4D700002B53F /* Roboto-Light.ttf */,
-				500B20911C4B4D700002B53F /* Roboto-Regular.ttf */,
-			);
-			name = font;
-			path = ../../font;
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		500B20601C4B4AB00002B53F /* tvOS_GL_ES */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 500B20771C4B4AB00002B53F /* Build configuration list for PBXNativeTarget "tvOS_GL_ES" */;
-			buildPhases = (
-				500B205D1C4B4AB00002B53F /* Sources */,
-				500B205E1C4B4AB00002B53F /* Frameworks */,
-				500B205F1C4B4AB00002B53F /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = tvOS_GL_ES;
-			productName = tvOS_GL_ES;
-			productReference = 500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */;
-			productType = "com.apple.product-type.application";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		500B20591C4B4AB00002B53F /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0720;
-				ORGANIZATIONNAME = richi;
-				TargetAttributes = {
-					500B20601C4B4AB00002B53F = {
-						CreatedOnToolsVersion = 7.2;
-					};
-				};
-			};
-			buildConfigurationList = 500B205C1C4B4AB00002B53F /* Build configuration list for PBXProject "tvOS_GL_ES" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = 500B20581C4B4AB00002B53F;
-			productRefGroup = 500B20621C4B4AB00002B53F /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				500B20601C4B4AB00002B53F /* tvOS_GL_ES */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		500B205F1C4B4AB00002B53F /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B20931C4B4D700002B53F /* Roboto-Bold.ttf in Resources */,
-				500B20921C4B4D700002B53F /* DroidSans.ttf in Resources */,
-				500B20951C4B4D700002B53F /* Roboto-Regular.ttf in Resources */,
-				500B20941C4B4D700002B53F /* Roboto-Light.ttf in Resources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		500B205D1C4B4AB00002B53F /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				500B20661C4B4AB00002B53F /* main.m in Sources */,
-				500B208C1C4B4D580002B53F /* zahnrad.c in Sources */,
-				500B208A1C4B4D460002B53F /* ZahnradBackend.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		500B20751C4B4AB00002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = appletvos;
-				TARGETED_DEVICE_FAMILY = 3;
-				TVOS_DEPLOYMENT_TARGET = 9.1;
-			};
-			name = Debug;
-		};
-		500B20761C4B4AB00002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = appletvos;
-				TARGETED_DEVICE_FAMILY = 3;
-				TVOS_DEPLOYMENT_TARGET = 9.1;
-				VALIDATE_PRODUCT = YES;
-			};
-			name = Release;
-		};
-		500B20781C4B4AB00002B53F /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				INFOPLIST_FILE = tvOS_GL_ES/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.tvOS-GL-ES";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Debug;
-		};
-		500B20791C4B4AB00002B53F /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				INFOPLIST_FILE = tvOS_GL_ES/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "com.richi.tvOS-GL-ES";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		500B205C1C4B4AB00002B53F /* Build configuration list for PBXProject "tvOS_GL_ES" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B20751C4B4AB00002B53F /* Debug */,
-				500B20761C4B4AB00002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		500B20771C4B4AB00002B53F /* Build configuration list for PBXNativeTarget "tvOS_GL_ES" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				500B20781C4B4AB00002B53F /* Debug */,
-				500B20791C4B4AB00002B53F /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 500B20591C4B4AB00002B53F /* Project object */;
-}

+ 0 - 7
demo/apple/tvOS_GL_ES.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:tvOS_GL_ES.xcodeproj">
-   </FileRef>
-</Workspace>

+ 0 - 32
demo/apple/tvOS_GL_ES/Info.plist

@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>UIMainStoryboardFile</key>
-	<string>Main</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>arm64</string>
-	</array>
-</dict>
-</plist>

+ 0 - 254
demo/apple/tvOS_GL_ES/main.m

@@ -1,254 +0,0 @@
-/*
- Copyright (c) 2016 richi
- 
- This software is provided 'as-is', without any express or implied
- warranty.  In no event will the authors be held liable for any damages
- arising from the use of this software.
- 
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 
- 1.  The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2.  Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3.  This notice may not be removed or altered from any source distribution.
- */
-
-#import <UIKit/UIKit.h>
-#import <GLKit/GLKit.h>
-
-#import "ZahnradBackend.h"
-
-
-@interface GameViewController : GLKViewController <UITextFieldDelegate>
-@end
-
-
-@implementation GameViewController
-{
-    NSUInteger keyboardHash;
-    UITextField* textInputField;
-    
-    CGPoint cursor;
-    UIView* cursorView;
-
-    EAGLContext* context;
-    ZahnradBackend* zr;
-    
-}
-
-
-- (void) viewDidLoad
-{
-    [super viewDidLoad];
-    
-    keyboardHash = -1;
-    
-    context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3];
-    assert(context != nil);
-    
-    ((GLKView*)self.view).context = context;
-    ((GLKView*)self.view).drawableDepthFormat = GLKViewDrawableDepthFormatNone;
-    
-    [EAGLContext setCurrentContext: context];
-    zr = [[ZahnradBackend alloc] initWithView: ((GLKView*)self.view)];
-    
-    UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action: @selector(pan:)];
-    [self.view addGestureRecognizer:panRecognizer];
-
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        cursor = CGPointMake(95, 70);
-        cursorView = [[UIView alloc] initWithFrame: CGRectMake(cursor.x, cursor.y, 10, 10)];
-        cursorView.backgroundColor = UIColor.redColor;
-        [self.view addSubview: cursorView];
-        [zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(cursor)}];
-    });
-}
-
-
-- (void) update
-{
-    [zr updateFrame];
-}
-
-
-- (void) glkView: (GLKView*) view drawInRect: (CGRect) rect
-{
-    CGRect bounds = view.bounds;
-    CGFloat scale = view.window.screen.scale;
-    
-    glClearColor(0, 0, 0, 1);
-    glClear(GL_COLOR_BUFFER_BIT);
-    
-    [zr drawFrameWithScale: scale width: bounds.size.width height: bounds.size.height];
-}
-
-
-#pragma mark - User Input -
-
-
-- (void) pan: (UIPanGestureRecognizer*) panRecognizer
-{
-    CGPoint delta = [panRecognizer translationInView: self.view];
-    
-#if 0
-    
-    CGFloat s = 33.0;
-    
-    cursor.x += delta.x / s;
-    cursor.y += delta.y / s;
-
-#else
-    
-    CGFloat s = 150.0;
-    
-    if (delta.x != 0.0)
-        cursor.x += pow(2.0, fabs(delta.x / s)) * (delta.x > 0.0 ? 1.0 : -1.0);
-    if (delta.y != 0.0)
-        cursor.y += pow(2.0, fabs(delta.y / s)) * (delta.y > 0.0 ? 1.0 : -1.0);
-#endif
-    
-    
-    CGRect bounds = self.view.bounds;
-    if (cursor.x < CGRectGetMinX(bounds)) cursor.x = CGRectGetMinX(bounds);
-    if (cursor.x > CGRectGetMaxX(bounds)) cursor.x = CGRectGetMaxX(bounds);
-    if (cursor.y < CGRectGetMinY(bounds)) cursor.y = CGRectGetMinY(bounds);
-    if (cursor.y > CGRectGetMaxY(bounds)) cursor.y = CGRectGetMaxY(bounds);
-    
-    cursorView.center = cursor;
-    
-    [zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(cursor)}];
-}
-
-
-- (void) pressesBegan: (NSSet*) presses withEvent: (UIPressesEvent*) event
-{
-    UIPress* press = [[event allPresses] anyObject];
-    if (press.type != UIPressTypeSelect) return;
-    
-    [zr addEvent: @{@"type" : @5, @"pos" : NSStringFromCGPoint(cursor)}];
-}
-
-
-- (void) pressesEnded: (NSSet*) presses withEvent: (UIPressesEvent*) event
-{
-    UIPress* press = [[event allPresses] anyObject];
-    if (press.type != UIPressTypeSelect) return;
-
-    [zr addEvent: @{@"type" : @6, @"pos" : NSStringFromCGPoint(cursor)}];
-}
-
-
-- (void) pressesCancelled: (NSSet*) presses withEvent: (UIPressesEvent*) event
-{
-    [self pressesEnded: presses withEvent: event];
-}
-
-
-
-- (BOOL) textFieldShouldReturn: (UITextField*) textField
-{
-    return YES;
-}
-
-
-- (void) textFieldDidEndEditing: (UITextField*) textField
-{
-    [textInputField resignFirstResponder];
-    [textInputField removeFromSuperview];
-    textInputField = nil;
-
-    [zr addEvent: @{@"type" : @12, @"txt" : textField.text, @"mod" : @0}];
-}
-
-
-- (void) showKeyboard: (NSDictionary*) info
-{
-    NSUInteger hash = [info[@"hash"] unsignedIntegerValue];
-    
-    if (hash != keyboardHash)
-    {
-        keyboardHash = hash;
-        if (!textInputField)
-        {
-            CGRect frame = CGRectFromString(info[@"frame"]);
-            textInputField = [[UITextField alloc] initWithFrame: frame];
-            textInputField.delegate = self;
-            textInputField.text = info[@"text"];
-            [self.view addSubview: textInputField];
-            [textInputField becomeFirstResponder];
-        }
-    }
-}
-
-
-- (void) hideKeyboard
-{
-    [textInputField resignFirstResponder];
-    [textInputField removeFromSuperview];
-    textInputField = nil;
-
-    keyboardHash = -1;
-}
-
-
-@end
-
-
-#pragma mark - App Delegate -
-
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow* window;
-@property (strong, nonatomic) GameViewController* gameViewController;
-
-@end
-
-
-@implementation AppDelegate
-
-
-- (void) showKeyboard: (NSDictionary*) info
-{
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self.gameViewController showKeyboard: info];
-    });
-}
-
-
-- (void) hideKeyboard
-{
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self.gameViewController hideKeyboard];
-    });
-}
-
-
-- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
-{
-    _window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
-    _gameViewController = [GameViewController new];
-    _window.rootViewController = _gameViewController;
-    [_window makeKeyAndVisible];
-    
-    return YES;
-}
-
-
-@end
-
-
-int main(int argc, char* argv[])
-{
-    @autoreleasepool
-    {
-        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-    }
-}
-
-

+ 0 - 2676
demo/demo.c

@@ -1,2676 +0,0 @@
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <assert.h>
-#include <stdarg.h>
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
-#ifndef CLAMP
-#define CLAMP(i,v,x) (MAX(MIN(v,x), i))
-#endif
-#define LEN(a)      (sizeof(a)/sizeof(a)[0])
-#define UNUSED(a)   ((void)(a))
-
-#define MAX_BUFFER  64
-#define MAX_MEMORY  (64 * 1024)
-#define MAX_COMMAND_MEMORY  (16 * 1024)
-#define WINDOW_WIDTH 1200
-#define WINDOW_HEIGHT 800
-
-struct icons {
-    struct zr_image unchecked;
-    struct zr_image checked;
-    struct zr_image rocket;
-    struct zr_image cloud;
-    struct zr_image pen;
-    struct zr_image play;
-    struct zr_image pause;
-    struct zr_image stop;
-    struct zr_image prev;
-    struct zr_image next;
-    struct zr_image tools;
-    struct zr_image dir;
-    struct zr_image copy;
-    struct zr_image convert;
-    struct zr_image del;
-    struct zr_image edit;
-    struct zr_image images[9];
-    struct zr_image menu[6];
-
-    struct zr_image desktop;
-    struct zr_image home;
-    struct zr_image computer;
-    struct zr_image directory;
-
-    struct zr_image default_file;
-    struct zr_image text_file;
-    struct zr_image music_file;
-    struct zr_image font_file;
-    struct zr_image img_file;
-    struct zr_image movie_file;
-
-    struct zr_image button;
-    struct zr_image button_hover;
-    struct zr_image check;
-    struct zr_image check_cursor;
-    struct zr_image close;
-    struct zr_image combo;
-    struct zr_image slider_cursor;
-    struct zr_image header;
-    struct zr_image window;
-};
-
-enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK};
-struct demo {
-    void *memory;
-    struct zr_context ctx;
-    struct icons icons;
-    enum theme theme;
-    struct zr_memory_status status;
-
-    int show_filex;
-    int show_simple;
-    int show_demo;
-    int show_node;
-    int show_grid;
-    int show_button;
-    int show_basic;
-};
-
-/* ===============================================================
- *
- *                          SIMPLE WINDOW
- *
- * ===============================================================*/
-static void
-simple_window(struct zr_context *ctx)
-{
-    /* simple demo window */
-    struct zr_panel layout;
-    if (zr_begin(ctx, &layout, "Show", zr_rect(420, 350, 200, 200),
-        ZR_WINDOW_BORDER|ZR_WINDOW_MOVABLE|ZR_WINDOW_SCALABLE|
-        ZR_WINDOW_CLOSABLE|ZR_WINDOW_MINIMIZABLE|ZR_WINDOW_TITLE))
-    {
-        enum {EASY, HARD};
-        static int op = EASY;
-        static int property = 20;
-
-        zr_layout_row_static(ctx, 30, 80, 1);
-        if (zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT)) {
-            /* event handling */
-        }
-        zr_layout_row_dynamic(ctx, 30, 2);
-        if (zr_option_label(ctx, "easy", op == EASY)) op = EASY;
-        if (zr_option_label(ctx, "hard", op == HARD)) op = HARD;
-
-        zr_layout_row_dynamic(ctx, 22, 1);
-        zr_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
-    }
-    zr_end(ctx);
-}
-
-/* ===============================================================
- *
- *                          DEMO WINDOW
- *
- * ===============================================================*/
-static void
-demo_window(struct demo *gui, struct zr_context *ctx)
-{
-    struct zr_panel menu;
-
-    /* window flags */
-    static int show_menu = zr_true;
-    static int titlebar = zr_true;
-    static int border = zr_true;
-    static int resize = zr_true;
-    static int moveable = zr_true;
-    static int no_scrollbar = zr_false;
-    static zr_flags window_flags = 0;
-    static int minimizable = zr_true;
-    static int close = zr_true;
-
-    /* popups */
-    static enum zr_style_header_align header_align = ZR_HEADER_RIGHT;
-    static int show_app_about = zr_false;
-    struct zr_panel layout;
-
-    /* window flags */
-    window_flags = 0;
-    ctx->style.window.header.align = header_align;
-    if (border) window_flags |= ZR_WINDOW_BORDER;
-    if (resize) window_flags |= ZR_WINDOW_SCALABLE;
-    if (moveable) window_flags |= ZR_WINDOW_MOVABLE;
-    if (no_scrollbar) window_flags |= ZR_WINDOW_NO_SCROLLBAR;
-    if (minimizable) window_flags |= ZR_WINDOW_MINIMIZABLE;
-    if (close) window_flags |= ZR_WINDOW_CLOSABLE;
-
-    if (zr_begin(ctx, &layout, "Demo", zr_rect(10, 10, 400, 750), window_flags))
-    {
-        if (show_menu)
-        {
-            /* menubar */
-            enum menu_states {MENU_DEFAULT, MENU_WINDOWS};
-            static enum menu_states menu_state = MENU_DEFAULT;
-            static zr_size mprog = 60;
-            static int mslider = 10;
-            static int mcheck = zr_true;
-
-            zr_menubar_begin(ctx);
-            zr_layout_row_begin(ctx, ZR_STATIC, 25, 2);
-            zr_layout_row_push(ctx, 45);
-            if (zr_menu_begin_label(ctx, &menu, "MENU", ZR_TEXT_LEFT, 120))
-            {
-                zr_layout_row_dynamic(ctx, 25, 1);
-                if (menu_state == MENU_DEFAULT) {
-                    static size_t prog = 40;
-                    static int slider = 10;
-                    static int check = zr_true;
-
-                    if (zr_menu_item_label(ctx, "Hide", ZR_TEXT_LEFT))
-                        show_menu = zr_false;
-                    if (zr_menu_item_label(ctx, "About", ZR_TEXT_LEFT))
-                        show_app_about = zr_true;
-                    zr_progress(ctx, &prog, 100, ZR_MODIFIABLE);
-                    zr_slider_int(ctx, 0, &slider, 16, 1);
-                    zr_checkbox_label(ctx, "check", &check);
-                    if (zr_button_symbol_label(ctx, ZR_SYMBOL_TRIANGLE_RIGHT,
-                            "Windows", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT))
-                        menu_state = MENU_WINDOWS;
-                } else {
-                    if (zr_selectable_label(ctx, "Simple", ZR_TEXT_LEFT, &gui->show_simple) && !gui->show_simple)
-                        zr_window_close(ctx, "Show");
-                    if (zr_selectable_label(ctx, "Node Editor", ZR_TEXT_LEFT, &gui->show_node) && !gui->show_node)
-                        zr_window_close(ctx, "Node Editor");
-                    #ifndef DEMO_DO_NOT_DRAW_IMAGES
-                    if (zr_selectable_label(ctx, "Grid", ZR_TEXT_LEFT, &gui->show_grid) && !gui->show_grid)
-                        zr_window_close(ctx, "Grid Demo");
-                    if (zr_selectable_label(ctx, "Basic", ZR_TEXT_LEFT, &gui->show_basic) && !gui->show_basic)
-                        zr_window_close(ctx, "Basic Demo");
-                    if (zr_selectable_label(ctx, "Button", ZR_TEXT_LEFT, &gui->show_button) && !gui->show_button)
-                        zr_window_close(ctx, "Button Demo");
-                    #endif
-                    if (zr_button_symbol_label(ctx, ZR_SYMBOL_TRIANGLE_LEFT,
-                            "Back", ZR_TEXT_RIGHT, ZR_BUTTON_DEFAULT))
-                        menu_state = MENU_DEFAULT;
-                }
-                zr_menu_end(ctx);
-            } else menu_state = MENU_DEFAULT;
-            zr_layout_row_push(ctx, 70);
-            zr_progress(ctx, &mprog, 100, ZR_MODIFIABLE);
-            zr_slider_int(ctx, 0, &mslider, 16, 1);
-            zr_checkbox_label(ctx, "check", &mcheck);
-            zr_menubar_end(ctx);
-        }
-
-        if (show_app_about)
-        {
-            /* about popup */
-            struct zr_panel popup;
-            static struct zr_rect s = {20, 100, 300, 190};
-            if (zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "About", ZR_WINDOW_CLOSABLE, s))
-            {
-                zr_layout_row_dynamic(ctx, 20, 1);
-                zr_label(ctx, "Zahnrad", ZR_TEXT_LEFT);
-                zr_label(ctx, "By Micha Mettke", ZR_TEXT_LEFT);
-                zr_label(ctx, "Zahnrad is licensed under the zlib License.",  ZR_TEXT_LEFT);
-                zr_label(ctx, "See LICENSE for more information", ZR_TEXT_LEFT);
-                zr_popup_end(ctx);
-            } else show_app_about = zr_false;
-        }
-
-        /* window flags */
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Window", ZR_MINIMIZED)) {
-            zr_layout_row_dynamic(ctx, 30, 2);
-            zr_checkbox_label(ctx, "Titlebar", &titlebar);
-            zr_checkbox_label(ctx, "Menu", &show_menu);
-            zr_checkbox_label(ctx, "Border", &border);
-            zr_checkbox_label(ctx, "Resizable", &resize);
-            zr_checkbox_label(ctx, "Moveable", &moveable);
-            zr_checkbox_label(ctx, "No Scrollbar", &no_scrollbar);
-            zr_checkbox_label(ctx, "Minimizable", &minimizable);
-            zr_checkbox_label(ctx, "Closeable", &close);
-            zr_layout_pop(ctx);
-        }
-
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Widgets", ZR_MINIMIZED))
-        {
-            enum options {A,B,C};
-            static int checkbox;
-            static int option;
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Text", ZR_MINIMIZED))
-            {
-                /* Text Widgets */
-                zr_layout_row_dynamic(ctx, 20, 1);
-                zr_label(ctx, "Label aligned left", ZR_TEXT_LEFT);
-                zr_label(ctx, "Label aligned centered", ZR_TEXT_CENTERED);
-                zr_label(ctx, "Label aligned right", ZR_TEXT_RIGHT);
-                zr_label_colored(ctx, "Blue text", ZR_TEXT_LEFT, zr_rgb(0,0,255));
-                zr_label_colored(ctx, "Yellow text", ZR_TEXT_LEFT, zr_rgb(255,255,0));
-                zr_text(ctx, "Text without /0", 15, ZR_TEXT_RIGHT);
-
-                zr_layout_row_static(ctx, 100, 200, 1);
-                zr_label_wrap(ctx, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping");
-                zr_layout_row_dynamic(ctx, 100, 1);
-                zr_label_wrap(ctx, "This is another long text to show dynamic window changes on multiline text");
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Button", ZR_MINIMIZED))
-            {
-                /* Buttons Widgets */
-                zr_layout_row_static(ctx, 30, 100, 3);
-                if (zr_button_label(ctx, "Button", ZR_BUTTON_DEFAULT))
-                    fprintf(stdout, "Button pressed!\n");
-                if (zr_button_label(ctx, "Repeater", ZR_BUTTON_REPEATER))
-                    fprintf(stdout, "Repeater is being pressed!\n");
-                zr_button_color(ctx, zr_rgb(0,0,255), ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_static(ctx, 20, 20, 8);
-                zr_button_symbol(ctx, ZR_SYMBOL_CIRCLE, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_CIRCLE_FILLED, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_RECT, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_RECT_FILLED, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_UP, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_DOWN, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_LEFT, ZR_BUTTON_DEFAULT);
-                zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_RIGHT, ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_static(ctx, 30, 100, 2);
-                zr_button_symbol_label(ctx, ZR_SYMBOL_TRIANGLE_LEFT, "prev", ZR_TEXT_RIGHT, ZR_BUTTON_DEFAULT);
-                zr_button_symbol_label(ctx, ZR_SYMBOL_TRIANGLE_RIGHT, "next", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT);
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Basic", ZR_MINIMIZED))
-            {
-                /* Basic widgets */
-                static int int_slider = 5;
-                static float float_slider = 2.5f;
-                static size_t prog_value = 40;
-                static float property_float = 2;
-                static int property_int = 10;
-                static int property_neg = 10;
-
-                static float range_float_min = 0;
-                static float range_float_max = 100;
-                static float range_float_value = 50;
-                static int range_int_min = 0;
-                static int range_int_value = 2048;
-                static int range_int_max = 4096;
-                static const float ratio[] = {120, 150};
-
-                zr_layout_row_static(ctx, 30, 100, 1);
-                zr_checkbox_label(ctx, "Checkbox", &checkbox);
-
-                zr_layout_row_static(ctx, 30, 80, 3);
-                option = zr_option_label(ctx, "optionA", option == A) ? A : option;
-                option = zr_option_label(ctx, "optionB", option == B) ? B : option;
-                option = zr_option_label(ctx, "optionC", option == C) ? C : option;
-
-
-                zr_layout_row(ctx, ZR_STATIC, 30, 2, ratio);
-                zr_labelf(ctx, ZR_TEXT_LEFT, "Slider int");
-                zr_slider_int(ctx, 0, &int_slider, 10, 1);
-
-                zr_label(ctx, "Slider float", ZR_TEXT_LEFT);
-                zr_slider_float(ctx, 0, &float_slider, 5.0, 0.5f);
-                zr_labelf(ctx, ZR_TEXT_LEFT, "Progressbar" , prog_value);
-                zr_progress(ctx, &prog_value, 100, ZR_MODIFIABLE);
-
-                zr_layout_row(ctx, ZR_STATIC, 25, 2, ratio);
-                zr_label(ctx, "Property float:", ZR_TEXT_LEFT);
-                zr_property_float(ctx, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f);
-                zr_label(ctx, "Property int:", ZR_TEXT_LEFT);
-                zr_property_int(ctx, "Int:", 0, &property_int, 100.0f, 1, 1);
-                zr_label(ctx, "Property neg:", ZR_TEXT_LEFT);
-                zr_property_int(ctx, "Neg:", -10, &property_neg, 10, 1, 1);
-
-                zr_layout_row_dynamic(ctx, 25, 1);
-                zr_label(ctx, "Range:", ZR_TEXT_LEFT);
-                zr_layout_row_dynamic(ctx, 25, 3);
-                zr_property_float(ctx, "#min:", 0, &range_float_min, range_float_max, 1.0f, 0.2f);
-                zr_property_float(ctx, "#float:", range_float_min, &range_float_value, range_float_max, 1.0f, 0.2f);
-                zr_property_float(ctx, "#max:", range_float_min, &range_float_max, 100, 1.0f, 0.2f);
-
-                zr_property_int(ctx, "#min:", INT_MIN, &range_int_min, range_int_max, 1, 10);
-                zr_property_int(ctx, "#neg:", range_int_min, &range_int_value, range_int_max, 1, 10);
-                zr_property_int(ctx, "#max:", range_int_min, &range_int_max, INT_MAX, 1, 10);
-
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Selectable", ZR_MINIMIZED))
-            {
-                if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "List", ZR_MINIMIZED))
-                {
-                    static int selected[4] = {zr_false, zr_false, zr_true, zr_false};
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    zr_selectable_label(ctx, "Selectable", ZR_TEXT_LEFT, &selected[0]);
-                    zr_selectable_label(ctx, "Selectable", ZR_TEXT_LEFT, &selected[1]);
-                    zr_label(ctx, "Not Selectable", ZR_TEXT_LEFT);
-                    zr_selectable_label(ctx, "Selectable", ZR_TEXT_LEFT, &selected[2]);
-                    zr_selectable_label(ctx, "Selectable", ZR_TEXT_LEFT, &selected[3]);
-                    zr_layout_pop(ctx);
-                }
-                if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Grid", ZR_MINIMIZED))
-                {
-                    int i;
-                    static int selected[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
-                    zr_layout_row_static(ctx, 50, 50, 4);
-                    for (i = 0; i < 16; ++i) {
-                        if (zr_selectable_label(ctx, "Z", ZR_TEXT_CENTERED, &selected[i])) {
-                            int x = (i % 4), y = i / 4;
-                            if (x > 0) selected[i - 1] ^= 1;
-                            if (x < 3) selected[i + 1] ^= 1;
-                            if (y > 0) selected[i - 4] ^= 1;
-                            if (y < 3) selected[i + 4] ^= 1;
-                        }
-                    }
-                    zr_layout_pop(ctx);
-                }
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Combo", ZR_MINIMIZED))
-            {
-                /* Combobox Widgets
-                 * In this library comboboxes are not limited to being a popup
-                 * list of selectable text. Instead it is a abstract concept of
-                 * having something that is *selected* or displayed, a popup window
-                 * which opens if something needs to be modified and the content
-                 * of the popup which causes the *selected* or displayed value to
-                 * change or if wanted close the combobox.
-                 *
-                 * While strange at first handling comboboxes in a abstract way
-                 * solves the problem of overloaded window content. For example
-                 * changing a color value requires 4 value modifier (slider, property,...)
-                 * for RGBA then you need a label and ways to display the current color.
-                 * If you want to go fancy you even add rgb and hsv ratio boxes.
-                 * While fine for one color if you have a lot of them it because
-                 * tedious to look at and quite wasteful in space. You could add
-                 * a popup which modifies the color but this does not solve the
-                 * fact that it still requires a lot of cluttered space to do.
-                 *
-                 * In these kind of instance abstract comboboxes are quite handy. All
-                 * value modifiers are hidden inside the combobox popup and only
-                 * the color is shown if not open. This combines the clarity of the
-                 * popup with the ease of use of just using the space for modifiers.
-                 *
-                 * Other instances are for example time and especially date picker,
-                 * which only show the currently activated time/data and hide the
-                 * selection logic inside the combobox popup.
-                 */
-                static float chart_selection = 8.0f;
-                static int current_weapon = 0;
-                static int check_values[5];
-                static float position[3];
-                static struct zr_color combo_color = {130, 50, 50, 255};
-                static struct zr_color combo_color2 = {130, 180, 50, 255};
-                static size_t prog_a =  20, prog_b = 40, prog_c = 10, prog_d = 90;
-                static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"};
-
-                char buffer[64];
-                size_t sum = 0;
-                struct zr_panel combo;
-
-                /* default combobox */
-                zr_layout_row_static(ctx, 25, 200, 1);
-                current_weapon = zr_combo(ctx, weapons, LEN(weapons), current_weapon, 25);
-
-                /* slider color combobox */
-                if (zr_combo_begin_color(ctx, &combo, combo_color, 200)) {
-                    float ratios[] = {0.15f, 0.85f};
-                    zr_layout_row(ctx, ZR_DYNAMIC, 30, 2, ratios);
-                    zr_label(ctx, "R:", ZR_TEXT_LEFT);
-                    combo_color.r = (zr_byte)zr_slide_int(ctx, 0, combo_color.r, 255, 5);
-                    zr_label(ctx, "G:", ZR_TEXT_LEFT);
-                    combo_color.g = (zr_byte)zr_slide_int(ctx, 0, combo_color.g, 255, 5);
-                    zr_label(ctx, "B:", ZR_TEXT_LEFT);
-                    combo_color.b = (zr_byte)zr_slide_int(ctx, 0, combo_color.b, 255, 5);
-                    zr_label(ctx, "A:", ZR_TEXT_LEFT);
-                    combo_color.a = (zr_byte)zr_slide_int(ctx, 0, combo_color.a , 255, 5);
-                    zr_combo_end(ctx);
-                }
-
-                /* complex color combobox */
-                if (zr_combo_begin_color(ctx, &combo, combo_color2, 400)) {
-                    enum color_mode {COL_RGB, COL_HSV};
-                    static int col_mode = COL_RGB;
-                    #ifndef DEMO_DO_NOT_USE_COLOR_PICKER
-                    zr_layout_row_dynamic(ctx, 120, 1);
-                    combo_color2 = zr_color_picker(ctx, combo_color2, ZR_RGBA);
-                    #endif
-
-                    zr_layout_row_dynamic(ctx, 25, 2);
-                    col_mode = zr_option_label(ctx, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode;
-                    col_mode = zr_option_label(ctx, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode;
-
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    if (col_mode == COL_RGB) {
-                        combo_color2.r = (zr_byte)zr_propertyi(ctx, "#R:", 0, combo_color2.r, 255, 1,1);
-                        combo_color2.g = (zr_byte)zr_propertyi(ctx, "#G:", 0, combo_color2.g, 255, 1,1);
-                        combo_color2.b = (zr_byte)zr_propertyi(ctx, "#B:", 0, combo_color2.b, 255, 1,1);
-                        combo_color2.a = (zr_byte)zr_propertyi(ctx, "#A:", 0, combo_color2.a, 255, 1,1);
-                    } else {
-                        zr_byte tmp[4];
-                        zr_color_hsva_bv(tmp, combo_color2);
-                        tmp[0] = (zr_byte)zr_propertyi(ctx, "#H:", 0, tmp[0], 255, 1,1);
-                        tmp[1] = (zr_byte)zr_propertyi(ctx, "#S:", 0, tmp[1], 255, 1,1);
-                        tmp[2] = (zr_byte)zr_propertyi(ctx, "#V:", 0, tmp[2], 255, 1,1);
-                        tmp[3] = (zr_byte)zr_propertyi(ctx, "#A:", 0, tmp[3], 255, 1,1);
-                        combo_color2 = zr_hsva_bv(tmp);
-                    }
-                    zr_combo_end(ctx);
-                }
-
-                /* progressbar combobox */
-                sum = prog_a + prog_b + prog_c + prog_d;
-                sprintf(buffer, "%lu", sum);
-                if (zr_combo_begin_label(ctx, &combo, buffer, 200)) {
-                    zr_layout_row_dynamic(ctx, 30, 1);
-                    zr_progress(ctx, &prog_a, 100, ZR_MODIFIABLE);
-                    zr_progress(ctx, &prog_b, 100, ZR_MODIFIABLE);
-                    zr_progress(ctx, &prog_c, 100, ZR_MODIFIABLE);
-                    zr_progress(ctx, &prog_d, 100, ZR_MODIFIABLE);
-                    zr_combo_end(ctx);
-                }
-
-                /* checkbox combobox */
-                sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]);
-                sprintf(buffer, "%lu", sum);
-                if (zr_combo_begin_label(ctx, &combo, buffer, 200)) {
-                    zr_layout_row_dynamic(ctx, 30, 1);
-                    zr_checkbox_label(ctx, weapons[0], &check_values[0]);
-                    zr_checkbox_label(ctx, weapons[1], &check_values[1]);
-                    zr_checkbox_label(ctx, weapons[2], &check_values[2]);
-                    zr_checkbox_label(ctx, weapons[3], &check_values[3]);
-                    zr_combo_end(ctx);
-                }
-
-                /* complex text combobox */
-                sprintf(buffer, "%.2f, %.2f, %.2f", position[0], position[1],position[2]);
-                if (zr_combo_begin_label(ctx, &combo, buffer, 200)) {
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    zr_property_float(ctx, "#X:", -1024.0f, &position[0], 1024.0f, 1,0.5f);
-                    zr_property_float(ctx, "#Y:", -1024.0f, &position[1], 1024.0f, 1,0.5f);
-                    zr_property_float(ctx, "#Z:", -1024.0f, &position[2], 1024.0f, 1,0.5f);
-                    zr_combo_end(ctx);
-                }
-
-                /* chart combobox */
-                sprintf(buffer, "%.1f", chart_selection);
-                if (zr_combo_begin_label(ctx, &combo, buffer, 250)) {
-                    size_t i = 0;
-                    static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f};
-                    zr_layout_row_dynamic(ctx, 150, 1);
-                    zr_chart_begin(ctx, ZR_CHART_COLUMN, LEN(values), 0, 50);
-                    for (i = 0; i < LEN(values); ++i) {
-                        zr_flags res = zr_chart_push(ctx, values[i]);
-                        if (res & ZR_CHART_CLICKED) {
-                            chart_selection = values[i];
-                            zr_combo_close(ctx);
-                        }
-                    }
-                    zr_chart_end(ctx);
-                    zr_combo_end(ctx);
-                }
-
-                {
-                    static int time_selected = 0;
-                    static int date_selected = 0;
-                    static struct tm sel_time;
-                    static struct tm sel_date;
-                    if (!time_selected || !date_selected) {
-                        /* keep time and date updated if nothing is selected */
-                        time_t cur_time = time(0);
-                        struct tm *n = localtime(&cur_time);
-                        if (!time_selected)
-                            memcpy(&sel_time, n, sizeof(struct tm));
-                        if (!date_selected)
-                            memcpy(&sel_date, n, sizeof(struct tm));
-                    }
-
-                    /* time combobox */
-                    sprintf(buffer, "%02d:%02d:%02d", sel_time.tm_hour, sel_time.tm_min, sel_time.tm_sec);
-                    if (zr_combo_begin_label(ctx, &combo, buffer, 250)) {
-                        time_selected = 1;
-                        zr_layout_row_dynamic(ctx, 25, 1);
-                        sel_time.tm_sec = zr_propertyi(ctx, "#S:", 0, sel_time.tm_sec, 60, 1, 1);
-                        sel_time.tm_min = zr_propertyi(ctx, "#M:", 0, sel_time.tm_min, 60, 1, 1);
-                        sel_time.tm_hour = zr_propertyi(ctx, "#H:", 0, sel_time.tm_hour, 23, 1, 1);
-                        zr_combo_end(ctx);
-                    }
-
-                    /* date combobox */
-                    zr_layout_row_static(ctx, 25, 350, 1);
-                    sprintf(buffer, "%02d-%02d-%02d", sel_date.tm_mday, sel_date.tm_mon+1, sel_date.tm_year+1900);
-                    if (zr_combo_begin_label(ctx, &combo, buffer, 400))
-                    {
-                        int i = 0;
-                        const char *month[] = {"January", "February", "March", "Apil", "May", "June", "July", "August", "September", "Ocotober", "November", "December"};
-                        const char *week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
-                        const int month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
-                        int year = sel_date.tm_year+1900;
-                        int leap_year = (!(year % 4) && ((year % 100))) || !(year % 400);
-                        int days = (sel_date.tm_mon == 1) ?
-                            month_days[sel_date.tm_mon] + leap_year:
-                            month_days[sel_date.tm_mon];
-
-                        /* header with month and year */
-                        date_selected = 1;
-                        zr_layout_row_begin(ctx, ZR_DYNAMIC, 20, 3);
-                        zr_layout_row_push(ctx, 0.05f);
-                        if (zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_LEFT, ZR_BUTTON_DEFAULT)) {
-                            if (sel_date.tm_mon == 0) {
-                                sel_date.tm_mon = 11;
-                                sel_date.tm_year = MAX(0, sel_date.tm_year-1);
-                            } else sel_date.tm_mon--;
-                        }
-                        zr_layout_row_push(ctx, 0.9f);
-                        sprintf(buffer, "%s %d", month[sel_date.tm_mon], year);
-                        zr_label(ctx, buffer, ZR_TEXT_CENTERED);
-                        zr_layout_row_push(ctx, 0.05f);
-                        if (zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_RIGHT, ZR_BUTTON_DEFAULT)) {
-                            if (sel_date.tm_mon == 11) {
-                                sel_date.tm_mon = 0;
-                                sel_date.tm_year++;
-                            } else sel_date.tm_mon++;
-                        }
-                        zr_layout_row_end(ctx);
-
-                        /* good old week day formula (double because precision) */
-                        {int year_n = (sel_date.tm_mon < 2) ? year-1: year;
-                        int y = year_n % 100;
-                        int c = year_n / 100;
-                        int y4 = (int)((float)y / 4);
-                        int c4 = (int)((float)c / 4);
-                        int m = (int)(2.6 * (double)(((sel_date.tm_mon + 10) % 12) + 1) - 0.2);
-                        int week_day = (((1 + m + y + y4 + c4 - 2 * c) % 7) + 7) % 7;
-
-                        /* weekdays  */
-                        zr_layout_row_dynamic(ctx, 35, 7);
-                        for (i = 0; i < (int)LEN(week_days); ++i)
-                            zr_label(ctx, week_days[i], ZR_TEXT_CENTERED);
-
-                        /* days  */
-                        if (week_day > 0) zr_spacing(ctx, week_day);
-                        for (i = 1; i <= days; ++i) {
-                            sprintf(buffer, "%d", i);
-                            if (zr_button_label(ctx, buffer, ZR_BUTTON_DEFAULT)) {
-                                sel_date.tm_mday = i;
-                                zr_combo_close(ctx);
-                            }
-                        }}
-                        zr_combo_end(ctx);
-                    }
-                }
-
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Input", ZR_MINIMIZED))
-            {
-                static const float ratio[] = {120, 150};
-                static char field_buffer[64];
-                static char text[9][64];
-                static size_t text_len[9];
-                static char box_buffer[512];
-                static size_t field_len;
-                static size_t box_len;
-                zr_flags active;
-
-                zr_layout_row(ctx, ZR_STATIC, 25, 2, ratio);
-                zr_label(ctx, "Default:", ZR_TEXT_LEFT);
-
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[0], &text_len[0], 64, zr_filter_default);
-                zr_label(ctx, "Int:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[1], &text_len[1], 64, zr_filter_decimal);
-                zr_label(ctx, "Float:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[2], &text_len[2], 64, zr_filter_float);
-                zr_label(ctx, "Hex:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[4], &text_len[4], 64, zr_filter_hex);
-                zr_label(ctx, "Octal:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[5], &text_len[5], 64, zr_filter_oct);
-                zr_label(ctx, "Binary:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_CURSOR, text[6], &text_len[6], 64, zr_filter_binary);
-
-                zr_label(ctx, "Password:", ZR_TEXT_LEFT);
-                {
-                    size_t i = 0;
-                    size_t old_len = text_len[8];
-                    char buffer[64];
-                    for (i = 0; i < text_len[8]; ++i) buffer[i] = '*';
-                    zr_edit_string(ctx, ZR_EDIT_SIMPLE, buffer, &text_len[8], 64, zr_filter_default);
-                    if (old_len < text_len[8])
-                        memcpy(&text[8][old_len], &buffer[old_len], text_len[8] - old_len);
-                }
-
-                zr_label(ctx, "Field:", ZR_TEXT_LEFT);
-                zr_edit_string(ctx, ZR_EDIT_FIELD, field_buffer, &field_len, 64, zr_filter_default);
-
-                zr_label(ctx, "Box:", ZR_TEXT_LEFT);
-                zr_layout_row_static(ctx, 180, 278, 1);
-                zr_edit_string(ctx, ZR_EDIT_BOX, box_buffer, &box_len, 512, zr_filter_default);
-
-                zr_layout_row(ctx, ZR_STATIC, 25, 2, ratio);
-                active = zr_edit_string(ctx, ZR_EDIT_FIELD|ZR_EDIT_SIGCOMIT, text[7], &text_len[7], 64,  zr_filter_ascii);
-                if (zr_button_label(ctx, "Submit", ZR_BUTTON_DEFAULT) ||
-                    (active & ZR_EDIT_COMMITED))
-                {
-                    text[7][text_len[7]] = '\n';
-                    text_len[7]++;
-                    memcpy(&box_buffer[box_len], &text[7], text_len[7]);
-                    box_len += text_len[7];
-                    text_len[7] = 0;
-                }
-                zr_layout_row_end(ctx);
-                zr_layout_pop(ctx);
-            }
-            zr_layout_pop(ctx);
-        }
-
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Chart", ZR_MINIMIZED))
-        {
-            /* Chart Widgets
-             * This library has two different rather simple charts. The line and the
-             * column chart. Both provide a simple way of visualizing values and
-             * have a retain mode and immedidate mode API version. For the retain
-             * mode version `zr_plot` and `zr_plot_function` you either provide
-             * an array or a callback to call to handle drawing the graph.
-             * For the immediate mode version you start by calling `zr_chart_begin`
-             * and need to provide min and max values for scaling on the Y-axis.
-             * and then call `zr_chart_push` to push values into the chart.
-             * Finally `zr_chart_end` needs to be called to end the process. */
-            float id = 0;
-            static int col_index = -1;
-            static int line_index = -1;
-            float step = (2*3.141592654f) / 32;
-
-            int i;
-            int index = -1;
-            struct zr_rect bounds;
-
-            /* line chart */
-            id = 0;
-            index = -1;
-            zr_layout_row_dynamic(ctx, 100, 1);
-            bounds = zr_widget_bounds(ctx);
-            if (zr_chart_begin(ctx, ZR_CHART_LINES, 32, -1.0f, 1.0f)) {
-                for (i = 0; i < 32; ++i) {
-                    zr_flags res = zr_chart_push(ctx, (float)cos(id));
-                    if (res & ZR_CHART_HOVERING)
-                        index = (int)i;
-                    if (res & ZR_CHART_CLICKED)
-                        line_index = (int)i;
-                    id += step;
-                }
-                zr_chart_end(ctx);
-            }
-
-            if (index != -1) {
-                char buffer[ZR_MAX_NUMBER_BUFFER];
-                float val = (float)cos((float)index*step);
-                sprintf(buffer, "Value: %.2f", val);
-                zr_tooltip(ctx, buffer);
-            }
-            if (line_index != -1) {
-                zr_layout_row_dynamic(ctx, 20, 1);
-                zr_labelf(ctx, ZR_TEXT_LEFT, "Selected value: %.2f", (float)cos((float)index*step));
-            }
-
-            /* column chart */
-            zr_layout_row_dynamic(ctx, 100, 1);
-            bounds = zr_widget_bounds(ctx);
-            if (zr_chart_begin(ctx, ZR_CHART_COLUMN, 32, 0.0f, 1.0f)) {
-                for (i = 0; i < 32; ++i) {
-                    zr_flags res = zr_chart_push(ctx, (float)fabs(sin(id)));
-                    if (res & ZR_CHART_HOVERING)
-                        index = (int)i;
-                    if (res & ZR_CHART_CLICKED)
-                        col_index = (int)i;
-                    id += step;
-                }
-                zr_chart_end(ctx);
-            }
-            if (index != -1) {
-                char buffer[ZR_MAX_NUMBER_BUFFER];
-                sprintf(buffer, "Value: %.2f", (float)fabs(sin(step * (float)index)));
-                zr_tooltip(ctx, buffer);
-            }
-            if (col_index != -1) {
-                zr_layout_row_dynamic(ctx, 20, 1);
-                zr_labelf(ctx, ZR_TEXT_LEFT, "Selected value: %.2f", (float)fabs(sin(step * (float)col_index)));
-            }
-            zr_layout_pop(ctx);
-        }
-
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Popup", ZR_MINIMIZED))
-        {
-            static struct zr_color color = {255,0,0, 255};
-            static int select[4];
-            static int popup_active;
-            const struct zr_input *in = &ctx->input;
-            struct zr_rect bounds;
-
-            /* menu contextual */
-            zr_layout_row_static(ctx, 30, 150, 1);
-            bounds = zr_widget_bounds(ctx);
-            zr_label(ctx, "Right click me for menu", ZR_TEXT_LEFT);
-
-            if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(100, 300), bounds)) {
-                static size_t prog = 40;
-                static int slider = 10;
-
-                zr_layout_row_dynamic(ctx, 25, 1);
-                zr_checkbox_label(ctx, "Menu", &show_menu);
-                zr_progress(ctx, &prog, 100, ZR_MODIFIABLE);
-                zr_slider_int(ctx, 0, &slider, 16, 1);
-                if (zr_contextual_item_label(ctx, "About", ZR_TEXT_CENTERED))
-                    show_app_about = zr_true;
-                zr_selectable_label(ctx, select[0]?"Unselect":"Select", ZR_TEXT_LEFT, &select[0]);
-                zr_selectable_label(ctx, select[1]?"Unselect":"Select", ZR_TEXT_LEFT, &select[1]);
-                zr_selectable_label(ctx, select[2]?"Unselect":"Select", ZR_TEXT_LEFT, &select[2]);
-                zr_selectable_label(ctx, select[3]?"Unselect":"Select", ZR_TEXT_LEFT, &select[3]);
-                zr_contextual_end(ctx);
-            }
-
-            /* color contextual */
-            zr_layout_row_begin(ctx, ZR_STATIC, 30, 2);
-            zr_layout_row_push(ctx, 100);
-            zr_label(ctx, "Right Click here:", ZR_TEXT_LEFT);
-            zr_layout_row_push(ctx, 50);
-            bounds = zr_widget_bounds(ctx);
-            zr_button_color(ctx, color, ZR_BUTTON_DEFAULT);
-            zr_layout_row_end(ctx);
-
-            if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(350, 60), bounds)) {
-                zr_layout_row_dynamic(ctx, 30, 4);
-                color.r = (zr_byte)zr_propertyi(ctx, "#r", 0, color.r, 255, 1, 1);
-                color.g = (zr_byte)zr_propertyi(ctx, "#g", 0, color.g, 255, 1, 1);
-                color.b = (zr_byte)zr_propertyi(ctx, "#b", 0, color.b, 255, 1, 1);
-                color.a = (zr_byte)zr_propertyi(ctx, "#a", 0, color.a, 255, 1, 1);
-                zr_contextual_end(ctx);
-            }
-
-            /* popup */
-            zr_layout_row_begin(ctx, ZR_STATIC, 30, 2);
-            zr_layout_row_push(ctx, 100);
-            zr_label(ctx, "Popup:", ZR_TEXT_LEFT);
-            zr_layout_row_push(ctx, 50);
-            if (zr_button_label(ctx, "Popup", ZR_BUTTON_DEFAULT))
-                popup_active = 1;
-            zr_layout_row_end(ctx);
-
-            if (popup_active)
-            {
-                static struct zr_rect s = {20, 100, 220, 150};
-                if (zr_popup_begin(ctx, &menu, ZR_POPUP_STATIC, "Error", ZR_WINDOW_DYNAMIC, s))
-                {
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    zr_label(ctx, "A terrible error as occured", ZR_TEXT_LEFT);
-                    zr_layout_row_dynamic(ctx, 25, 2);
-                    if (zr_button_label(ctx, "OK", ZR_BUTTON_DEFAULT)) {
-                        popup_active = 0;
-                        zr_popup_close(ctx);
-                    }
-                    if (zr_button_label(ctx, "Cancel", ZR_BUTTON_DEFAULT)) {
-                        popup_active = 0;
-                        zr_popup_close(ctx);
-                    }
-                    zr_popup_end(ctx);
-                } else popup_active = zr_false;
-            }
-
-            /* tooltip */
-            zr_layout_row_static(ctx, 30, 150, 1);
-            bounds = zr_widget_bounds(ctx);
-            zr_label(ctx, "Hover me for tooltip", ZR_TEXT_LEFT);
-            if (zr_input_is_mouse_hovering_rect(in, bounds))
-                zr_tooltip(ctx, "This is a tooltip");
-
-            zr_layout_pop(ctx);
-        }
-
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Layout", ZR_MINIMIZED))
-        {
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Widget", ZR_MINIMIZED))
-            {
-                float ratio_two[] = {0.2f, 0.6f, 0.2f};
-                float width_two[] = {100, 200, 50};
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Dynamic fixed column layout with generated position and size:", ZR_TEXT_LEFT);
-                zr_layout_row_dynamic(ctx, 30, 3);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "static fixed column layout with generated position and size:", ZR_TEXT_LEFT);
-                zr_layout_row_static(ctx, 30, 100, 3);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Dynamic array-based custom column layout with generated position and custom size:",ZR_TEXT_LEFT);
-                zr_layout_row(ctx, ZR_DYNAMIC, 30, 3, ratio_two);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Static array-based custom column layout with generated position and custom size:",ZR_TEXT_LEFT );
-                zr_layout_row(ctx, ZR_STATIC, 30, 3, width_two);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Dynamic immediate mode custom column layout with generated position and custom size:",ZR_TEXT_LEFT);
-                zr_layout_row_begin(ctx, ZR_DYNAMIC, 30, 3);
-                zr_layout_row_push(ctx, 0.2f);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_push(ctx, 0.6f);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_push(ctx, 0.2f);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_end(ctx);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Static immmediate mode custom column layout with generated position and custom size:", ZR_TEXT_LEFT);
-                zr_layout_row_begin(ctx, ZR_STATIC, 30, 3);
-                zr_layout_row_push(ctx, 100);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_push(ctx, 200);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_push(ctx, 50);
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_row_end(ctx);
-
-                zr_layout_row_dynamic(ctx, 30, 1);
-                zr_label(ctx, "Static free space with custom position and custom size:", ZR_TEXT_LEFT);
-                zr_layout_space_begin(ctx, ZR_STATIC, 120, 4);
-                zr_layout_space_push(ctx, zr_rect(100, 0, 100, 30));
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_space_push(ctx, zr_rect(0, 15, 100, 30));
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_space_push(ctx, zr_rect(200, 15, 100, 30));
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_space_push(ctx, zr_rect(100, 30, 100, 30));
-                zr_button_label(ctx, "button", ZR_BUTTON_DEFAULT);
-                zr_layout_space_end(ctx);
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Group", ZR_MINIMIZED))
-            {
-                static int group_titlebar = zr_false;
-                static int group_border = zr_true;
-                static int group_no_scrollbar = zr_false;
-                static int group_width = 320;
-                static int group_height = 200;
-                struct zr_panel tab;
-
-                zr_flags group_flags = 0;
-                if (group_border) group_flags |= ZR_WINDOW_BORDER;
-                if (group_no_scrollbar) group_flags |= ZR_WINDOW_NO_SCROLLBAR;
-                if (group_titlebar) group_flags |= ZR_WINDOW_TITLE;
-
-                zr_layout_row_dynamic(ctx, 30, 3);
-                zr_checkbox_label(ctx, "Titlebar", &group_titlebar);
-                zr_checkbox_label(ctx, "Border", &group_border);
-                zr_checkbox_label(ctx, "No Scrollbar", &group_no_scrollbar);
-
-                zr_layout_row_begin(ctx, ZR_STATIC, 22, 2);
-                zr_layout_row_push(ctx, 50);
-                zr_label(ctx, "size:", ZR_TEXT_LEFT);
-                zr_layout_row_push(ctx, 130);
-                zr_property_int(ctx, "#Width:", 100, &group_width, 500, 10, 1);
-                zr_layout_row_push(ctx, 130);
-                zr_property_int(ctx, "#Height:", 100, &group_height, 500, 10, 1);
-                zr_layout_row_end(ctx);
-
-                zr_layout_row_static(ctx, (float)group_height, group_width, 2);
-                if (zr_group_begin(ctx, &tab, "Group", group_flags)) {
-                    int i = 0;
-                    static int selected[16];
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    for (i = 0; i < 16; ++i)
-                        zr_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]);
-                    zr_group_end(ctx);
-                }
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Simple", ZR_MINIMIZED))
-            {
-                struct zr_panel tab;
-                zr_layout_row_dynamic(ctx, 300, 2);
-                if (zr_group_begin(ctx, &tab, "Group_Without_Border", 0)) {
-                    int i = 0;
-                    char buffer[64];
-                    zr_layout_row_static(ctx, 18, 150, 1);
-                    for (i = 0; i < 64; ++i) {
-                        sprintf(buffer, "0x%02x", i);
-                        zr_labelf(ctx, ZR_TEXT_LEFT, "%s: scrollable region", buffer);
-                    }
-                    zr_group_end(ctx);
-                }
-                if (zr_group_begin(ctx, &tab, "Group_With_Border", ZR_WINDOW_BORDER)) {
-                    int i = 0;
-                    char buffer[64];
-                    zr_layout_row_dynamic(ctx, 25, 2);
-                    for (i = 0; i < 64; ++i) {
-                        sprintf(buffer, "%08d", ((((i%7)*10)^32))+(64+(i%2)*2));
-                        zr_button_label(ctx, buffer, ZR_BUTTON_DEFAULT);
-                    }
-                    zr_group_end(ctx);
-                }
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Complex", ZR_MINIMIZED))
-            {
-                int i;
-                struct zr_panel tab;
-                zr_layout_space_begin(ctx, ZR_STATIC, 500, 64);
-                zr_layout_space_push(ctx, zr_rect(0,0,150,500));
-                if (zr_group_begin(ctx, &tab, "Group_left", ZR_WINDOW_BORDER)) {
-                    static int selected[32];
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    for (i = 0; i < 32; ++i)
-                        zr_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]);
-                    zr_group_end(ctx);
-                }
-
-                zr_layout_space_push(ctx, zr_rect(160,0,150,240));
-                if (zr_group_begin(ctx, &tab, "Group_top", ZR_WINDOW_BORDER)) {
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                    zr_group_end(ctx);
-                }
-
-                zr_layout_space_push(ctx, zr_rect(160,250,150,250));
-                if (zr_group_begin(ctx, &tab, "Group_buttom", ZR_WINDOW_BORDER)) {
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                    zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                    zr_group_end(ctx);
-                }
-
-                zr_layout_space_push(ctx, zr_rect(320,0,150,150));
-                if (zr_group_begin(ctx, &tab, "Group_right_top", ZR_WINDOW_BORDER)) {
-                    static int selected[4];
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    for (i = 0; i < 4; ++i)
-                        zr_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]);
-                    zr_group_end(ctx);
-                }
-
-                zr_layout_space_push(ctx, zr_rect(320,160,150,150));
-                if (zr_group_begin(ctx, &tab, "Group_right_center", ZR_WINDOW_BORDER)) {
-                    static int selected[4];
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    for (i = 0; i < 4; ++i)
-                        zr_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]);
-                    zr_group_end(ctx);
-                }
-
-                zr_layout_space_push(ctx, zr_rect(320,320,150,150));
-                if (zr_group_begin(ctx, &tab, "Group_right_bottom", ZR_WINDOW_BORDER)) {
-                    static int selected[4];
-                    zr_layout_row_static(ctx, 18, 100, 1);
-                    for (i = 0; i < 4; ++i)
-                        zr_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]);
-                    zr_group_end(ctx);
-                }
-                zr_layout_space_end(ctx);
-                zr_layout_pop(ctx);
-            }
-
-            if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Splitter", ZR_MINIMIZED))
-            {
-                const struct zr_input *in = &ctx->input;
-                zr_layout_row_static(ctx, 20, 320, 1);
-                zr_label(ctx, "Use slider and spinner to change tile size", ZR_TEXT_LEFT);
-                zr_label(ctx, "Drag the space between tiles to change tile ratio", ZR_TEXT_LEFT);
-
-                if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Vertical", ZR_MINIMIZED))
-                {
-                    static float a = 100, b = 100, c = 100;
-                    struct zr_rect bounds;
-                    struct zr_panel sub;
-
-                    float row_layout[5];
-                    row_layout[0] = a;
-                    row_layout[1] = 8;
-                    row_layout[2] = b;
-                    row_layout[3] = 8;
-                    row_layout[4] = c;
-
-                    /* header */
-                    zr_layout_row_static(ctx, 30, 100, 2);
-                    zr_label(ctx, "left:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
-
-                    zr_label(ctx, "middle:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
-
-                    zr_label(ctx, "right:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
-
-                    /* tiles */
-                    zr_layout_row(ctx, ZR_STATIC, 200, 5, row_layout);
-
-                    /* left space */
-                    if (zr_group_begin(ctx, &sub, "left", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR)) {
-                        zr_layout_row_dynamic(ctx, 25, 1);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-
-                    /* scaler */
-                    bounds = zr_widget_bounds(ctx);
-                    zr_spacing(ctx, 1);
-                    if ((zr_input_is_mouse_hovering_rect(in, bounds) ||
-                        zr_input_is_mouse_prev_hovering_rect(in, bounds)) &&
-                        zr_input_is_mouse_down(in, ZR_BUTTON_LEFT))
-                    {
-                        a = row_layout[0] + in->mouse.delta.x;
-                        b = row_layout[2] - in->mouse.delta.x;
-                    }
-
-                    /* middle space */
-                    if (zr_group_begin(ctx, &sub, "center", ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR)) {
-                        zr_layout_row_dynamic(ctx, 25, 1);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-
-                    /* scaler */
-                    bounds = zr_widget_bounds(ctx);
-                    zr_spacing(ctx, 1);
-                    if ((zr_input_is_mouse_hovering_rect(in, bounds) ||
-                        zr_input_is_mouse_prev_hovering_rect(in, bounds)) &&
-                        zr_input_is_mouse_down(in, ZR_BUTTON_LEFT))
-                    {
-                        b = (row_layout[2] + in->mouse.delta.x);
-                        c = (row_layout[4] - in->mouse.delta.x);
-                    }
-
-                    /* right space */
-                    if (zr_group_begin(ctx, &sub, "right", ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR)) {
-                        zr_layout_row_dynamic(ctx, 25, 1);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-
-                    zr_layout_pop(ctx);
-                }
-
-                if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Horizontal", ZR_MINIMIZED))
-                {
-                    static float a = 100, b = 100, c = 100;
-                    struct zr_panel sub;
-                    struct zr_rect bounds;
-
-                    /* header */
-                    zr_layout_row_static(ctx, 30, 100, 2);
-                    zr_label(ctx, "top:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
-
-                    zr_label(ctx, "middle:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
-
-                    zr_label(ctx, "bottom:", ZR_TEXT_LEFT);
-                    zr_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
-
-                    /* top space */
-                    zr_layout_row_dynamic(ctx, a, 1);
-                    if (zr_group_begin(ctx, &sub, "top", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) {
-                        zr_layout_row_dynamic(ctx, 25, 3);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-
-                    /* scaler */
-                    zr_layout_row_dynamic(ctx, 8, 1);
-                    bounds = zr_widget_bounds(ctx);
-                    zr_spacing(ctx, 1);
-                    if ((zr_input_is_mouse_hovering_rect(in, bounds) ||
-                        zr_input_is_mouse_prev_hovering_rect(in, bounds)) &&
-                        zr_input_is_mouse_down(in, ZR_BUTTON_LEFT))
-                    {
-                        a = a + in->mouse.delta.y;
-                        b = b - in->mouse.delta.y;
-                    }
-
-                    /* middle space */
-                    zr_layout_row_dynamic(ctx, b, 1);
-                    if (zr_group_begin(ctx, &sub, "middle", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) {
-                        zr_layout_row_dynamic(ctx, 25, 3);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-
-                    {
-                        /* scaler */
-                        zr_layout_row_dynamic(ctx, 8, 1);
-                        bounds = zr_widget_bounds(ctx);
-                        if ((zr_input_is_mouse_hovering_rect(in, bounds) ||
-                            zr_input_is_mouse_prev_hovering_rect(in, bounds)) &&
-                            zr_input_is_mouse_down(in, ZR_BUTTON_LEFT))
-                        {
-                            b = b + in->mouse.delta.y;
-                            c = c - in->mouse.delta.y;
-                        }
-                    }
-
-                    /* bottom space */
-                    zr_layout_row_dynamic(ctx, c, 1);
-                    if (zr_group_begin(ctx, &sub, "bottom", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) {
-                        zr_layout_row_dynamic(ctx, 25, 3);
-                        zr_button_label(ctx, "#FFAA", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFBB", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFCC", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFDD", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFEE", ZR_BUTTON_DEFAULT);
-                        zr_button_label(ctx, "#FFFF", ZR_BUTTON_DEFAULT);
-                        zr_group_end(ctx);
-                    }
-                    zr_layout_pop(ctx);
-                }
-                zr_layout_pop(ctx);
-            }
-            zr_layout_pop(ctx);
-        }
-    }
-    zr_end(ctx);
-}
-
-/* ===============================================================
- *
- *                          CUSTOM WIDGET
- *
- * ===============================================================*/
-static int
-ui_piemenu(struct zr_context *ctx, struct zr_vec2 pos, float radius,
-            struct zr_image *icons, int item_count)
-{
-    int ret = -1;
-    struct zr_rect total_space;
-    struct zr_panel popup;
-    struct zr_rect bounds;
-    int active_item = 0;
-
-    /* pie menu popup */
-    struct zr_color border = ctx->style.window.border_color;
-    struct zr_style_item background = ctx->style.window.fixed_background;
-    ctx->style.window.fixed_background = zr_style_item_hide();
-    ctx->style.window.border_color = zr_rgba(0,0,0,0);
-
-    total_space  = zr_window_get_content_region(ctx);
-    zr_popup_begin(ctx, &popup,  ZR_POPUP_STATIC, "piemenu", ZR_WINDOW_NO_SCROLLBAR,
-        zr_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y,
-        2*radius,2*radius));
-
-    total_space = zr_window_get_content_region(ctx);
-    zr_layout_row_dynamic(ctx, total_space.h, 1);
-    {
-        int i = 0;
-        struct zr_command_buffer* out = zr_window_get_canvas(ctx);
-        const struct zr_input *in = &ctx->input;
-        {
-            /* allocate complete popup space for the menu */
-            enum zr_widget_layout_states state;
-            total_space = zr_window_get_content_region(ctx);
-            total_space.x = total_space.y = 0;
-            state = zr_widget(&bounds, ctx);
-        }
-
-        /* outer circle */
-        zr_fill_circle(out, bounds, zr_rgb(50,50,50));
-        {
-            /* circle buttons */
-            float step = (2 * 3.141592654f) / (float)(MAX(1,item_count));
-            float a_min = 0; float a_max = step;
-
-            struct zr_vec2 center = zr_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f);
-            struct zr_vec2 drag = zr_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y);
-            float angle = (float)atan2(drag.y, drag.x);
-            if (angle < -0.0f) angle += 2.0f * 3.141592654f;
-            active_item = (int)(angle/step);
-
-            for (i = 0; i < item_count; ++i) {
-                struct zr_rect content;
-                float rx, ry, dx, dy, a;
-                zr_fill_arc(out, center.x, center.y, (bounds.w/2.0f),
-                    a_min, a_max, (active_item == i) ? zr_rgb(45,100,255): zr_rgb(60,60,60));
-
-                /* seperator line */
-                rx = bounds.w/2.0f; ry = 0;
-                dx = rx * (float)cos(a_min) - ry * (float)sin(a_min);
-                dy = rx * (float)sin(a_min) + ry * (float)cos(a_min);
-                zr_stroke_line(out, center.x, center.y,
-                    center.x + dx, center.y + dy, 1.0f, zr_rgb(50,50,50));
-
-                /* button content */
-                a = a_min + (a_max - a_min)/2.0f;
-                rx = bounds.w/2.5f; ry = 0;
-                content.w = 30; content.h = 30;
-                content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f);
-                content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f);
-                zr_draw_image(out, content, &icons[i]);
-                a_min = a_max; a_max += step;
-            }
-        }
-        {
-            /* inner circle */
-            struct zr_rect inner;
-            inner.x = bounds.x + bounds.w/2 - bounds.w/4;
-            inner.y = bounds.y + bounds.h/2 - bounds.h/4;
-            inner.w = bounds.w/2; inner.h = bounds.h/2;
-            zr_fill_circle(out, inner, zr_rgb(45,45,45));
-
-            /* active icon content */
-            bounds.w = inner.w / 2.0f;
-            bounds.h = inner.h / 2.0f;
-            bounds.x = inner.x + inner.w/2 - bounds.w/2;
-            bounds.y = inner.y + inner.h/2 - bounds.h/2;
-            zr_draw_image(out, bounds, &icons[active_item]);
-        }
-    }
-    zr_layout_space_end(ctx);
-    zr_popup_end(ctx);
-
-    ctx->style.window.fixed_background = background;
-    ctx->style.window.border_color = border;
-
-    if (!zr_input_is_mouse_down(&ctx->input, ZR_BUTTON_RIGHT))
-        return active_item;
-    else return ret;
-}
-
-/* ===============================================================
- *
- *                          GRID
- *
- * ===============================================================*/
-static void
-grid_demo(struct zr_context *ctx)
-{
-    static char text[3][64];
-    static size_t text_len[3];
-    static const char *items[] = {"Item 0","item 1","item 2"};
-    static int selected_item = 0;
-    static int check = 1;
-    struct zr_panel layout;
-
-    int i;
-    struct zr_panel combo;
-    ctx->style.font.height = 20;
-    if (zr_begin(ctx, &layout, "Grid Demo", zr_rect(600, 350, 275, 250),
-        ZR_WINDOW_TITLE|ZR_WINDOW_BORDER|ZR_WINDOW_MOVABLE|
-        ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_NO_SCROLLBAR))
-    {
-        ctx->style.font.height = 18;
-        zr_layout_row_dynamic(ctx, 30, 2);
-        zr_label(ctx, "Floating point:", ZR_TEXT_RIGHT);
-        zr_edit_string(ctx, ZR_EDIT_FIELD, text[0], &text_len[0], 64, zr_filter_float);
-        zr_label(ctx, "Hexadeximal:", ZR_TEXT_RIGHT);
-        zr_edit_string(ctx, ZR_EDIT_FIELD, text[1], &text_len[1], 64, zr_filter_hex);
-        zr_label(ctx, "Binary:", ZR_TEXT_RIGHT);
-        zr_edit_string(ctx, ZR_EDIT_FIELD, text[2], &text_len[2], 64, zr_filter_binary);
-        zr_label(ctx, "Checkbox:", ZR_TEXT_RIGHT);
-        zr_checkbox_label(ctx, "Check me", &check);
-        zr_label(ctx, "Combobox:", ZR_TEXT_RIGHT);
-
-        if (zr_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
-            zr_layout_row_dynamic(ctx, 30, 1);
-            for (i = 0; i < 3; ++i)
-                if (zr_combo_item_label(ctx, items[i], ZR_TEXT_LEFT))
-                    selected_item = i;
-            zr_combo_end(ctx);
-        }
-    }
-    zr_end(ctx);
-    ctx->style.font.height = 14;
-}
-
-/* ===============================================================
- *
- *                          BUTTON DEMO
- *
- * ===============================================================*/
-static void
-ui_header(struct zr_context *ctx, const char *title)
-{
-    ctx->style.font.height = 18;
-    zr_layout_row_dynamic(ctx, 20, 1);
-    zr_label(ctx, title, ZR_TEXT_LEFT);
-}
-
-static void
-ui_widget(struct zr_context *ctx, float height, float font_height)
-{
-    static const float ratio[] = {0.15f, 0.85f};
-    ctx->style.font.height = font_height;
-    zr_layout_row(ctx, ZR_DYNAMIC, height, 2, ratio);
-    zr_spacing(ctx, 1);
-}
-
-static void
-ui_widget_centered(struct zr_context *ctx, float height, float font_height)
-{
-    static const float ratio[] = {0.15f, 0.50f, 0.35f};
-    ctx->style.font.height = font_height;
-    zr_layout_row(ctx, ZR_DYNAMIC, height, 3, ratio);
-    zr_spacing(ctx, 1);
-}
-
-static void
-button_demo(struct zr_context *ctx, struct icons *img)
-{
-    struct zr_panel layout;
-    struct zr_panel menu;
-    static int option = 1;
-    static int toggle0 = 1;
-    static int toggle1 = 0;
-    static int toggle2 = 1;
-
-    ctx->style.font.height = 20;
-    zr_begin(ctx, &layout, "Button Demo", zr_rect(50,50,255,610),
-        ZR_WINDOW_BORDER|ZR_WINDOW_MOVABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_TITLE);
-
-    /*------------------------------------------------
-     *                  MENU
-     *------------------------------------------------*/
-    zr_menubar_begin(ctx);
-    {
-        /* toolbar */
-        zr_layout_row_static(ctx, 40, 40, 4);
-        if (zr_menu_begin_image(ctx, &menu, "Music", img->play, 120))
-        {
-            /* settings */
-            zr_layout_row_dynamic(ctx, 25, 1);
-            zr_menu_item_image_label(ctx, img->play, "Play", ZR_TEXT_RIGHT);
-            zr_menu_item_image_label(ctx, img->stop, "Stop", ZR_TEXT_RIGHT);
-            zr_menu_item_image_label(ctx, img->pause, "Pause", ZR_TEXT_RIGHT);
-            zr_menu_item_image_label(ctx, img->next, "Next", ZR_TEXT_RIGHT);
-            zr_menu_item_image_label(ctx, img->prev, "Prev", ZR_TEXT_RIGHT);
-            zr_menu_end(ctx);
-        }
-        zr_button_image(ctx, img->tools, ZR_BUTTON_DEFAULT);
-        zr_button_image(ctx, img->cloud, ZR_BUTTON_DEFAULT);
-        zr_button_image(ctx, img->pen, ZR_BUTTON_DEFAULT);
-    }
-    zr_menubar_end(ctx);
-
-    /*------------------------------------------------
-     *                  BUTTON
-     *------------------------------------------------*/
-    ui_header(ctx, "Push buttons");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_label(ctx, "Push me", ZR_BUTTON_DEFAULT))
-        fprintf(stdout, "pushed!\n");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_image_label(ctx, img->rocket, "Styled", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT))
-        fprintf(stdout, "rocket!\n");
-
-    /*------------------------------------------------
-     *                  REPEATER
-     *------------------------------------------------*/
-    ui_header(ctx, "Repeater");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_label(ctx, "Press me", ZR_BUTTON_REPEATER))
-        fprintf(stdout, "pressed!\n");
-
-    /*------------------------------------------------
-     *                  TOGGLE
-     *------------------------------------------------*/
-    ui_header(ctx, "Toggle buttons");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_image_label(ctx, (toggle0) ? img->checked: img->unchecked,
-        "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle0 = !toggle0;
-
-    ui_widget(ctx, 35, 22);
-    if (zr_button_image_label(ctx, (toggle1) ? img->checked: img->unchecked,
-        "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle1 = !toggle1;
-
-    ui_widget(ctx, 35, 22);
-    if (zr_button_image_label(ctx, (toggle2) ? img->checked: img->unchecked,
-        "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle2 = !toggle2;
-
-    /*------------------------------------------------
-     *                  RADIO
-     *------------------------------------------------*/
-    ui_header(ctx, "Radio buttons");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_symbol_label(ctx, (option == 0)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE,
-            "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 0;
-    ui_widget(ctx, 35, 22);
-    if (zr_button_symbol_label(ctx, (option == 1)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE,
-            "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 1;
-    ui_widget(ctx, 35, 22);
-    if (zr_button_symbol_label(ctx, (option == 2)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE,
-            "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 2;
-
-    /*------------------------------------------------
-     *                  CONTEXTUAL
-     *------------------------------------------------*/
-    if (zr_contextual_begin(ctx, &menu, ZR_WINDOW_NO_SCROLLBAR, zr_vec2(120, 200), zr_window_get_bounds(ctx))) {
-        ctx->style.font.height = 18;
-        zr_layout_row_dynamic(ctx, 25, 1);
-        if (zr_contextual_item_image_label(ctx, img->copy, "Clone", ZR_TEXT_RIGHT))
-            fprintf(stdout, "pressed clone!\n");
-        if (zr_contextual_item_image_label(ctx, img->del, "Delete", ZR_TEXT_RIGHT))
-            fprintf(stdout, "pressed delete!\n");
-        if (zr_contextual_item_image_label(ctx, img->convert, "Convert", ZR_TEXT_RIGHT))
-            fprintf(stdout, "pressed convert!\n");
-        if (zr_contextual_item_image_label(ctx, img->edit, "Edit", ZR_TEXT_RIGHT))
-            fprintf(stdout, "pressed edit!\n");
-        zr_contextual_end(ctx);
-    }
-    ctx->style.font.height = 14;
-    zr_end(ctx);
-}
-
-/* ===============================================================
- *
- *                          BASIC DEMO
- *
- * ===============================================================*/
-static void
-basic_demo(struct zr_context *ctx, struct icons *img)
-{
-    static int image_active;
-    static int check0 = 1;
-    static int check1 = 0;
-    static size_t prog = 80;
-    static int selected_item = 0;
-    static int selected_image = 3;
-    static int selected_icon = 0;
-    static const char *items[] = {"Item 0","item 1","item 2"};
-    static int piemenu_active = 0;
-    static struct zr_vec2 piemenu_pos;
-
-    int i = 0;
-    struct zr_panel layout;
-    struct zr_panel combo;
-    ctx->style.font.height = 20;
-    zr_begin(ctx, &layout, "Basic Demo", zr_rect(320, 50, 275, 610),
-        ZR_WINDOW_BORDER|ZR_WINDOW_MOVABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_TITLE);
-
-    /*------------------------------------------------
-     *                  POPUP BUTTON
-     *------------------------------------------------*/
-    ui_header(ctx, "Popup & Scrollbar & Images");
-    ui_widget(ctx, 35, 22);
-    if (zr_button_image_label(ctx, img->dir,
-        "Images", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT))
-        image_active = !image_active;
-
-    /*------------------------------------------------
-     *                  SELECTED IMAGE
-     *------------------------------------------------*/
-    ui_header(ctx, "Selected Image");
-    ui_widget_centered(ctx, 100, 22);
-    zr_image(ctx, img->images[selected_image]);
-
-    /*------------------------------------------------
-     *                  IMAGE POPUP
-     *------------------------------------------------*/
-    if (image_active) {
-        struct zr_panel popup;
-        if (zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "Image Popup", 0, zr_rect(265, 0, 320, 220))) {
-            zr_layout_row_static(ctx, 82, 82, 3);
-            for (i = 0; i < 9; ++i) {
-                if (zr_button_image(ctx, img->images[i], ZR_BUTTON_DEFAULT)) {
-                    selected_image = i;
-                    image_active = 0;
-                    zr_popup_close(ctx);
-                }
-            }
-            zr_popup_end(ctx);
-        }
-    }
-    /*------------------------------------------------
-     *                  COMBOBOX
-     *------------------------------------------------*/
-    ui_header(ctx, "Combo box");
-    ui_widget(ctx, 40, 22);
-    if (zr_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
-        zr_layout_row_dynamic(ctx, 35, 1);
-        for (i = 0; i < 3; ++i)
-            if (zr_combo_item_label(ctx, items[i], ZR_TEXT_LEFT))
-                selected_item = i;
-        zr_combo_end(ctx);
-    }
-
-    ui_widget(ctx, 40, 22);
-    if (zr_combo_begin_image_label(ctx, &combo, items[selected_icon], img->images[selected_icon], 200)) {
-        zr_layout_row_dynamic(ctx, 35, 1);
-        for (i = 0; i < 3; ++i)
-            if (zr_combo_item_image_label(ctx, img->images[i], items[i], ZR_TEXT_RIGHT))
-                selected_icon = i;
-        zr_combo_end(ctx);
-    }
-
-    /*------------------------------------------------
-     *                  CHECKBOX
-     *------------------------------------------------*/
-    ui_header(ctx, "Checkbox");
-    ui_widget(ctx, 30, 22);
-    zr_checkbox_label(ctx, "Flag 1", &check0);
-    ui_widget(ctx, 30, 22);
-    zr_checkbox_label(ctx, "Flag 2", &check1);
-
-    /*------------------------------------------------
-     *                  PROGRESSBAR
-     *------------------------------------------------*/
-    ui_header(ctx, "Progressbar");
-    ui_widget(ctx, 35, 22);
-    zr_progress(ctx, &prog, 100, zr_true);
-
-    /*------------------------------------------------
-     *                  PIEMENU
-     *------------------------------------------------*/
-    if (zr_input_is_mouse_click_down_in_rect(&ctx->input, ZR_BUTTON_RIGHT,
-        layout.bounds,zr_true)){
-        piemenu_pos = ctx->input.mouse.pos;
-        piemenu_active = 1;
-    }
-
-    if (piemenu_active) {
-        int ret = ui_piemenu(ctx, piemenu_pos, 140, &img->menu[0], 6);
-        if (ret != -1) {
-            fprintf(stdout, "piemenu selected: %d\n", ret);
-            piemenu_active = 0;
-        }
-    }
-    ctx->style.font.height = 14;
-    zr_end(ctx);
-}
-/* ===============================================================
- *
- *                          FILE BROWSER
- *
- * ===============================================================*/
-/* sorry only works for posix systems right now because of the directory function */
-enum file_groups {
-    FILE_GROUP_DEFAULT,
-    FILE_GROUP_TEXT,
-    FILE_GROUP_MUSIC,
-    FILE_GROUP_FONT,
-    FILE_GROUP_IMAGE,
-    FILE_GROUP_MOVIE,
-    FILE_GROUP_MAX
-};
-
-enum file_types {
-    FILE_DEFAULT,
-    FILE_TEXT,
-    FILE_C_SOURCE,
-    FILE_CPP_SOURCE,
-    FILE_HEADER,
-    FILE_CPP_HEADER,
-    FILE_MP3,
-    FILE_WAV,
-    FILE_OGG,
-    FILE_TTF,
-    FILE_BMP,
-    FILE_PNG,
-    FILE_JPEG,
-    FILE_PCX,
-    FILE_TGA,
-    FILE_GIF,
-    FILE_MAX
-};
-
-struct file_group {
-    enum file_groups group;
-    const char *name;
-    struct zr_image *icon;
-};
-
-struct file {
-    enum file_types type;
-    const char *suffix;
-    enum file_groups group;
-};
-
-struct media {
-    int font;
-    int icon_sheet;
-    struct icons *icons;
-    struct file_group group[FILE_GROUP_MAX];
-    struct file files[FILE_MAX];
-};
-
-#define MAX_PATH_LEN 512
-struct file_browser {
-    /* path */
-    char file[MAX_PATH_LEN];
-    char home[MAX_PATH_LEN];
-    char desktop[MAX_PATH_LEN];
-    char directory[MAX_PATH_LEN];
-
-    /* directory content */
-    char **files;
-    char **directories;
-    size_t file_count;
-    size_t dir_count;
-    struct media media;
-};
-
-#ifndef DEMO_DO_NOT_DRAW_IMAGES
-#ifdef __unix__
-
-#include <dirent.h>
-#include <unistd.h>
-
-#ifndef _WIN32
-# include <pwd.h>
-#endif
-
-static char*
-str_duplicate(const char *src)
-{
-    char *ret;
-    size_t len = strlen(src);
-    if (!len) return 0;
-    ret = (char*)malloc(len+1);
-    if (!ret) return 0;
-    memcpy(ret, src, len);
-    ret[len] = '\0';
-    return ret;
-}
-
-static void
-dir_free_list(char **list, size_t size)
-{
-    size_t i;
-    for (i = 0; i < size; ++i)
-        free(list[i]);
-    free(list);
-}
-
-static char**
-dir_list(const char *dir, int return_subdirs, size_t *count)
-{
-    size_t n = 0;
-    char buffer[MAX_PATH_LEN];
-    char **results = NULL;
-    const DIR *none = NULL;
-    size_t capacity = 32;
-    size_t size;
-    DIR *z;
-
-    assert(dir);
-    assert(count);
-    strncpy(buffer, dir, MAX_PATH_LEN);
-    n = strlen(buffer);
-
-    if (n > 0 && (buffer[n-1] != '/'))
-        buffer[n++] = '/';
-
-    size = 0;
-
-    z = opendir(dir);
-    if (z != none) {
-        int nonempty = 1;
-        struct dirent *data = readdir(z);
-        nonempty = (data != NULL);
-        if (!nonempty) return NULL;
-
-        do {
-            DIR *y;
-            char *p;
-            int is_subdir;
-            if (data->d_name[0] == '.')
-                continue;
-
-            strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);
-            y = opendir(buffer);
-            is_subdir = (y != NULL);
-            if (y != NULL) closedir(y);
-
-            if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){
-                if (!size) {
-                    results = (char**)calloc(sizeof(char*), capacity);
-                } else if (size >= capacity) {
-                    capacity = capacity * 2;
-                    results = (char**)realloc(results, capacity * sizeof(char*));
-                }
-                p = str_duplicate(data->d_name);
-                results[size++] = p;
-            }
-        } while ((data = readdir(z)) != NULL);
-    }
-
-    if (z) closedir(z);
-    *count = size;
-    return results;
-}
-
-static struct file_group
-FILE_GROUP(enum file_groups group, const char *name, struct zr_image *icon)
-{
-    struct file_group fg;
-    fg.group = group;
-    fg.name = name;
-    fg.icon = icon;
-    return fg;
-}
-
-static struct file
-FILE_DEF(enum file_types type, const char *suffix, enum file_groups group)
-{
-    struct file fd;
-    fd.type = type;
-    fd.suffix = suffix;
-    fd.group = group;
-    return fd;
-}
-
-static struct zr_image*
-media_icon_for_file(struct media *media, const char *file)
-{
-    int i = 0;
-    const char *s = file;
-    char suffix[4];
-    int found = 0;
-    memset(suffix, 0, sizeof(suffix));
-
-    /* extract suffix .xxx from file */
-    while (*s++ != '\0') {
-        if (found && i < 3)
-            suffix[i++] = *s;
-
-        if (*s == '.') {
-            if (found){
-                found = 0;
-                break;
-            }
-            found = 1;
-        }
-    }
-
-    /* check for all file definition of all groups for fitting suffix*/
-    for (i = 0; i < FILE_MAX && found; ++i) {
-        struct file *d = &media->files[i];
-        {
-            const char *f = d->suffix;
-            s = suffix;
-            while (f && *f && *s && *s == *f) {
-                s++; f++;
-            }
-
-            /* found correct file definition so */
-            if (f && *s == '\0' && *f == '\0')
-                return media->group[d->group].icon;
-        }
-    }
-    return &media->icons->default_file;
-}
-
-static void
-media_init(struct media *media, struct icons *icons)
-{
-    /* file groups */
-    media->icons = icons;
-    media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file);
-    media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file);
-    media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file);
-    media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file);
-    media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file);
-    media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file);
-
-    /* files */
-    media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);
-    media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT);
-    media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT);
-    media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT);
-    media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT);
-    media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT);
-    media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC);
-    media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC);
-    media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC);
-    media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT);
-    media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE);
-    media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE);
-    media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE);
-    media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE);
-    media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE);
-    media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE);
-}
-
-static void
-file_browser_reload_directory_content(struct file_browser *browser, const char *path)
-{
-    strncpy(browser->directory, path, MAX_PATH_LEN);
-    dir_free_list(browser->files, browser->file_count);
-    dir_free_list(browser->directories, browser->dir_count);
-    browser->files = dir_list(path, 0, &browser->file_count);
-    browser->directories = dir_list(path, 1, &browser->dir_count);
-}
-
-static void
-file_browser_init(struct file_browser *browser, struct icons *icons)
-{
-    memset(browser, 0, sizeof(*browser));
-    media_init(&browser->media, icons);
-    {
-        /* load files and sub-directory list */
-        const char *home = getenv("HOME");
-#ifdef _WIN32
-        if (!home) home = getenv("USERPROFILE");
-#else
-        if (!home) home = getpwuid(getuid())->pw_dir;
-        {
-            size_t l;
-            strncpy(browser->home, home, MAX_PATH_LEN);
-            l = strlen(browser->home);
-            strcpy(browser->home + l, "/");
-            strcpy(browser->directory, browser->home);
-        }
-#endif
-        {
-            size_t l;
-            strcpy(browser->desktop, browser->home);
-            l = strlen(browser->desktop);
-            strcpy(browser->desktop + l, "desktop/");
-        }
-        browser->files = dir_list(browser->directory, 0, &browser->file_count);
-        browser->directories = dir_list(browser->directory, 1, &browser->dir_count);
-    }
-}
-
-static void
-file_browser_free(struct file_browser *browser)
-{
-    if (browser->files)
-        dir_free_list(browser->files, browser->file_count);
-    if (browser->directories)
-        dir_free_list(browser->directories, browser->dir_count);
-    browser->files = NULL;
-    browser->directories = NULL;
-    memset(browser, 0, sizeof(*browser));
-}
-
-static int
-file_browser_run(struct file_browser *browser, struct zr_context *ctx)
-{
-    int ret = 0;
-    struct zr_panel layout;
-    struct media *media = &browser->media;
-    struct icons *icons = media->icons;
-    struct zr_rect total_space;
-
-    if (zr_begin(ctx, &layout, "File Browser", zr_rect(50, 50, 800, 600),
-        ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSABLE|ZR_WINDOW_MOVABLE))
-    {
-        struct zr_panel sub;
-        static float ratio[] = {0.25f, ZR_UNDEFINED};
-        float spacing_x = ctx->style.window.spacing.x;
-
-        /* output path directory selector in the menubar */
-        ctx->style.window.spacing.x = 0;
-        zr_menubar_begin(ctx);
-        {
-            char *d = browser->directory;
-            char *begin = d + 1;
-            zr_layout_row_dynamic(ctx, 25, 6);
-            while (*d++) {
-                if (*d == '/') {
-                    *d = '\0';
-                    if (zr_button_label(ctx, begin, ZR_BUTTON_DEFAULT)) {
-                        *d++ = '/'; *d = '\0';
-                        file_browser_reload_directory_content(browser, browser->directory);
-                        break;
-                    }
-                    *d = '/';
-                    begin = d + 1;
-                }
-            }
-        }
-        zr_menubar_end(ctx);
-        ctx->style.window.spacing.x = spacing_x;
-
-        /* window layout */
-        total_space = zr_window_get_content_region(ctx);
-        zr_layout_row(ctx, ZR_DYNAMIC, total_space.h, 2, ratio);
-        zr_group_begin(ctx, &sub, "Special", ZR_WINDOW_NO_SCROLLBAR);
-        {
-            struct zr_image home = icons->home;
-            struct zr_image desktop = icons->desktop;
-            struct zr_image computer = icons->computer;
-
-            zr_layout_row_dynamic(ctx, 40, 1);
-            if (zr_button_image_label(ctx, home, "home", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT))
-                file_browser_reload_directory_content(browser, browser->home);
-            if (zr_button_image_label(ctx,desktop,"desktop",ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT))
-                file_browser_reload_directory_content(browser, browser->desktop);
-            if (zr_button_image_label(ctx,computer,"computer",ZR_TEXT_CENTERED,ZR_BUTTON_DEFAULT))
-                file_browser_reload_directory_content(browser, "/");
-            zr_group_end(ctx);
-        }
-
-        /* output directory content window */
-        zr_group_begin(ctx, &sub, "Content", 0);
-        {
-            int index = -1;
-            size_t i = 0, j = 0, k = 0;
-            size_t rows = 0, cols = 0;
-            size_t count = browser->dir_count + browser->file_count;
-
-            cols = 4;
-            rows = count / cols;
-            for (i = 0; i <= rows; i += 1) {
-                {size_t n = j + cols;
-                zr_layout_row_dynamic(ctx, 135, (int)cols);
-                for (; j < count && j < n; ++j) {
-                    /* draw one row of icons */
-                    if (j < browser->dir_count) {
-                        /* draw and execute directory buttons */
-                        if (zr_button_image(ctx,icons->directory,ZR_BUTTON_DEFAULT))
-                            index = (int)j;
-                    } else {
-                        /* draw and execute files buttons */
-                        struct zr_image *icon;
-                        size_t fileIndex = ((size_t)j - browser->dir_count);
-                        icon = media_icon_for_file(media,browser->files[fileIndex]);
-                        if (zr_button_image(ctx, *icon, ZR_BUTTON_DEFAULT)) {
-                            strncpy(browser->file, browser->directory, MAX_PATH_LEN);
-                            n = strlen(browser->file);
-                            strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);
-                            ret = 1;
-                        }
-                    }
-                }}
-                {size_t n = k + cols;
-                zr_layout_row_dynamic(ctx, 20, (int)cols);
-                for (; k < count && k < n; k++) {
-                    /* draw one row of labels */
-                    if (k < browser->dir_count) {
-                        zr_label(ctx, browser->directories[k], ZR_TEXT_CENTERED);
-                    } else {
-                        size_t t = k-browser->dir_count;
-                        zr_label(ctx,browser->files[t],ZR_TEXT_CENTERED);
-                    }
-                }}
-            }
-
-            if (index != -1) {
-                size_t n = strlen(browser->directory);
-                strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);
-                n = strlen(browser->directory);
-                if (n < MAX_PATH_LEN - 1) {
-                    browser->directory[n] = '/';
-                    browser->directory[n+1] = '\0';
-                }
-                file_browser_reload_directory_content(browser, browser->directory);
-            }
-            zr_group_end(ctx);
-        }
-    }
-    zr_end(ctx);
-    return ret;
-}
-#endif
-#endif
-
-/* ===============================================================
- *
- *                          NODE EDITOR
- *
- * ===============================================================*/
-struct node {
-    int ID;
-    char name[32];
-    struct zr_rect bounds;
-    float value;
-    struct zr_color color;
-    int input_count;
-    int output_count;
-    struct node *next;
-    struct node *prev;
-};
-
-struct node_link {
-    int input_id;
-    int input_slot;
-    int output_id;
-    int output_slot;
-    struct zr_vec2 in;
-    struct zr_vec2 out;
-};
-
-struct node_linking {
-    int active;
-    struct node *node;
-    int input_id;
-    int input_slot;
-};
-
-struct node_editor {
-    struct node node_buf[32];
-    struct node_link links[64];
-    struct node *begin;
-    struct node *end;
-    int node_count;
-    int link_count;
-    struct zr_rect bounds;
-    struct node *selected;
-    int show_grid;
-    struct zr_vec2 scrolling;
-    struct node_linking linking;
-};
-
-static void
-node_editor_push(struct node_editor *editor, struct node *node)
-{
-    if (!editor->begin) {
-        node->next = NULL;
-        node->prev = NULL;
-        editor->begin = node;
-        editor->end = node;
-    } else {
-        node->prev = editor->end;
-        if (editor->end)
-            editor->end->next = node;
-        node->next = NULL;
-        editor->end = node;
-    }
-}
-
-static void
-node_editor_pop(struct node_editor *editor, struct node *node)
-{
-    if (node->next)
-        node->next->prev = node->prev;
-    if (node->prev)
-        node->prev->next = node->next;
-    if (editor->end == node)
-        editor->end = node->prev;
-    if (editor->begin == node)
-        editor->begin = node->next;
-    node->next = NULL;
-    node->prev = NULL;
-}
-
-static struct node*
-node_editor_find(struct node_editor *editor, int ID)
-{
-    struct node *iter = editor->begin;
-    while (iter) {
-        if (iter->ID == ID)
-            return iter;
-        iter = iter->next;
-    }
-    return NULL;
-}
-
-static void
-node_editor_add(struct node_editor *editor, const char *name, struct zr_rect bounds,
-    struct zr_color col, int in_count, int out_count)
-{
-    static int IDs = 0;
-    struct node *node;
-    assert((zr_size)editor->node_count < LEN(editor->node_buf));
-    node = &editor->node_buf[editor->node_count++];
-    node->ID = IDs++;
-    node->value = 0;
-    node->color = zr_rgb(255, 0, 0);
-    node->input_count = in_count;
-    node->output_count = out_count;
-    node->color = col;
-    node->bounds = bounds;
-    strcpy(node->name, name);
-    node_editor_push(editor, node);
-}
-
-static void
-node_editor_link(struct node_editor *editor, int in_id, int in_slot,
-    int out_id, int out_slot)
-{
-    struct node_link *link;
-    assert((zr_size)editor->link_count < LEN(editor->links));
-    link = &editor->links[editor->link_count++];
-    link->input_id = in_id;
-    link->input_slot = in_slot;
-    link->output_id = out_id;
-    link->output_slot = out_slot;
-}
-
-static void
-node_editor_demo(struct zr_context *ctx, struct node_editor *nodedit)
-{
-    int n = 0;
-    struct zr_rect total_space;
-    const struct zr_input *in = &ctx->input;
-    struct zr_command_buffer *canvas;
-    struct node *updated = 0;
-    struct zr_panel layout;
-
-    /* This is a simple node editor just to show a simple implementation and that
-     * it is possible to achieve with this library. While all nodes inside this
-     * example use a simple color modifier as content you could change them
-     * to have your custom content depending on the node time.
-     * Biggest difference to most usual implementation is that this example does
-     * not has connectors on the right position of the property that it links.
-     * This is mainly done out of lazyness and could be implemented as well but
-     * requires calculating the position of all rows and add connectors.
-     * In addition adding and removing nodes is quite limited at the
-     * moment since it is based on a simple fixed array. If this is to be converted
-     * into something more serious it is probably best to extend it.*/
-
-    if (zr_begin(ctx, &layout, "Node Editor", zr_rect(50, 50, 650, 650),
-        ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSABLE|ZR_WINDOW_MOVABLE))
-    {
-        /* allocate complete window space */
-        canvas = zr_window_get_canvas(ctx);
-        total_space = zr_window_get_content_region(ctx);
-        zr_layout_space_begin(ctx, ZR_STATIC, total_space.h, nodedit->node_count);
-        {
-            struct zr_panel node, menu;
-            struct node *it = nodedit->begin;
-            struct zr_rect size = zr_layout_space_bounds(ctx);
-
-            if (nodedit->show_grid) {
-                /* display grid */
-                float x, y;
-                const float grid_size = 32.0f;
-                const struct zr_color grid_color = zr_rgb(50, 50, 50);
-                for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size)
-                    zr_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color);
-                for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size)
-                    zr_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color);
-            }
-
-            /* execute each node as a moveable group */
-            while (it) {
-                /* calculate scrolled node window position and size */
-                zr_layout_space_push(ctx, zr_rect(it->bounds.x - nodedit->scrolling.x,
-                    it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h));
-
-                /* execute node window */
-                if (zr_group_begin(ctx, &node, it->name, ZR_WINDOW_MOVABLE|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER|ZR_WINDOW_TITLE))
-                {
-                    /* always have last selected node on top */
-                    if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, node.bounds) &&
-                        (!(it->prev && zr_input_mouse_clicked(in, ZR_BUTTON_LEFT,
-                        zr_layout_space_rect_to_screen(ctx, node.bounds)))) &&
-                        nodedit->end != it)
-                    {
-                        updated = it;
-                    }
-
-                    /* ================= NODE CONTENT =====================*/
-                    zr_layout_row_dynamic(ctx, 25, 1);
-                    zr_button_color(ctx, it->color, ZR_BUTTON_DEFAULT);
-                    it->color.r = (zr_byte)zr_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1);
-                    it->color.g = (zr_byte)zr_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1);
-                    it->color.b = (zr_byte)zr_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1);
-                    it->color.a = (zr_byte)zr_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1);
-                    /* ====================================================*/
-                    zr_group_end(ctx);
-                }
-                {
-                    /* node connector and linking */
-                    float space;
-                    struct zr_rect bounds;
-                    bounds = zr_layout_space_rect_to_local(ctx, node.bounds);
-                    bounds.x += nodedit->scrolling.x;
-                    bounds.y += nodedit->scrolling.y;
-                    it->bounds = bounds;
-
-                    /* output connector */
-                    space = node.bounds.h / (float)((it->output_count) + 1);
-                    for (n = 0; n < it->output_count; ++n) {
-                        struct zr_rect circle;
-                        circle.x = node.bounds.x + node.bounds.w-4;
-                        circle.y = node.bounds.y + space * (float)(n+1);
-                        circle.w = 8; circle.h = 8;
-                        zr_fill_circle(canvas, circle, zr_rgb(100, 100, 100));
-
-                        /* start linking process */
-                        if (zr_input_has_mouse_click_down_in_rect(in, ZR_BUTTON_LEFT, circle, zr_true)) {
-                            nodedit->linking.active = zr_true;
-                            nodedit->linking.node = it;
-                            nodedit->linking.input_id = it->ID;
-                            nodedit->linking.input_slot = n;
-                        }
-
-                        /* draw curve from linked node slot to mouse position */
-                        if (nodedit->linking.active && nodedit->linking.node == it &&
-                            nodedit->linking.input_slot == n) {
-                            struct zr_vec2 l0 = zr_vec2(circle.x + 3, circle.y + 3);
-                            struct zr_vec2 l1 = in->mouse.pos;
-                            zr_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
-                                l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, zr_rgb(100, 100, 100));
-                        }
-                    }
-
-                    /* input connector */
-                    space = node.bounds.h / (float)((it->input_count) + 1);
-                    for (n = 0; n < it->input_count; ++n) {
-                        struct zr_rect circle;
-                        circle.x = node.bounds.x-4;
-                        circle.y = node.bounds.y + space * (float)(n+1);
-                        circle.w = 8; circle.h = 8;
-                        zr_fill_circle(canvas, circle, zr_rgb(100, 100, 100));
-                        if (zr_input_is_mouse_released(in, ZR_BUTTON_LEFT) &&
-                            zr_input_is_mouse_hovering_rect(in, circle) &&
-                            nodedit->linking.active && nodedit->linking.node != it) {
-                            nodedit->linking.active = zr_false;
-                            node_editor_link(nodedit, nodedit->linking.input_id,
-                                nodedit->linking.input_slot, it->ID, n);
-                        }
-                    }
-                }
-                it = it->next;
-            }
-
-            /* reset linking connection */
-            if (nodedit->linking.active && zr_input_is_mouse_released(in, ZR_BUTTON_LEFT)) {
-                nodedit->linking.active = zr_false;
-                nodedit->linking.node = NULL;
-                fprintf(stdout, "linking failed\n");
-            }
-
-            /* draw each link */
-            for (n = 0; n < nodedit->link_count; ++n) {
-                struct node_link *link = &nodedit->links[n];
-                struct node *ni = node_editor_find(nodedit, link->input_id);
-                struct node *no = node_editor_find(nodedit, link->output_id);
-                float spacei = node.bounds.h / (float)((ni->output_count) + 1);
-                float spaceo = node.bounds.h / (float)((no->input_count) + 1);
-                struct zr_vec2 l0 = zr_layout_space_to_screen(ctx,
-                    zr_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1)));
-                struct zr_vec2 l1 = zr_layout_space_to_screen(ctx,
-                    zr_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1)));
-
-                l0.x -= nodedit->scrolling.x;
-                l0.y -= nodedit->scrolling.y;
-                l1.x -= nodedit->scrolling.x;
-                l1.y -= nodedit->scrolling.y;
-                zr_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
-                    l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, zr_rgb(100, 100, 100));
-            }
-
-            if (updated) {
-                /* reshuffle nodes to have least recently selected node on top */
-                node_editor_pop(nodedit, updated);
-                node_editor_push(nodedit, updated);
-            }
-
-            /* node selection */
-            if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, zr_layout_space_bounds(ctx))) {
-                it = nodedit->begin;
-                nodedit->selected = NULL;
-                nodedit->bounds = zr_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
-                while (it) {
-                    struct zr_rect b = zr_layout_space_rect_to_screen(ctx, it->bounds);
-                    b.x -= nodedit->scrolling.x;
-                    b.y -= nodedit->scrolling.y;
-                    if (zr_input_is_mouse_hovering_rect(in, b))
-                        nodedit->selected = it;
-                    it = it->next;
-                }
-            }
-
-            /* contextual menu */
-            if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(100, 220), zr_window_get_bounds(ctx))) {
-                const char *grid_option[] = {"Show Grid", "Hide Grid"};
-                zr_layout_row_dynamic(ctx, 25, 1);
-                if (zr_contextual_item_label(ctx, "New", ZR_TEXT_CENTERED))
-                    node_editor_add(nodedit, "New", zr_rect(400, 260, 180, 220),
-                            zr_rgb(255, 255, 255), 1, 2);
-                if (zr_contextual_item_label(ctx, grid_option[nodedit->show_grid],ZR_TEXT_CENTERED))
-                    nodedit->show_grid = !nodedit->show_grid;
-                zr_contextual_end(ctx);
-            }
-        }
-        zr_layout_space_end(ctx);
-
-        /* window content scrolling */
-        if (zr_input_is_mouse_hovering_rect(in, zr_window_get_bounds(ctx)) &&
-            zr_input_is_mouse_down(in, ZR_BUTTON_MIDDLE)) {
-            nodedit->scrolling.x += in->mouse.delta.x;
-            nodedit->scrolling.y += in->mouse.delta.y;
-        }
-    }
-    zr_end(ctx);
-}
-
-static void
-node_editor_init(struct node_editor *editor)
-{
-    memset(editor, 0, sizeof(*editor));
-    editor->begin = NULL;
-    editor->end = NULL;
-    node_editor_add(editor, "Source", zr_rect(40, 10, 180, 220), zr_rgb(255, 0, 0), 0, 1);
-    node_editor_add(editor, "Source", zr_rect(40, 260, 180, 220), zr_rgb(0, 255, 0), 0, 1);
-    node_editor_add(editor, "Combine", zr_rect(400, 100, 180, 220), zr_rgb(0,0,255), 2, 2);
-    node_editor_link(editor, 0, 0, 2, 0);
-    node_editor_link(editor, 1, 0, 2, 1);
-    editor->show_grid = zr_true;
-}
-
-/* ===============================================================
- *
- *                          CONTROL WINDOW
- *
- * ===============================================================*/
-static void
-set_style(struct zr_context *ctx, enum theme theme)
-{
-    struct zr_color table[ZR_COLOR_COUNT];
-    if (theme == THEME_WHITE) {
-        table[ZR_COLOR_TEXT] = zr_rgba(70, 70, 70, 255);
-        table[ZR_COLOR_WINDOW] = zr_rgba(175, 175, 175, 255);
-        table[ZR_COLOR_HEADER] = zr_rgba(175, 175, 175, 255);
-        table[ZR_COLOR_BORDER] = zr_rgba(0, 0, 0, 255);
-        table[ZR_COLOR_BUTTON] = zr_rgba(185, 185, 185, 255);
-        table[ZR_COLOR_BUTTON_HOVER] = zr_rgba(170, 170, 170, 255);
-        table[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(160, 160, 160, 255);
-        table[ZR_COLOR_TOGGLE] = zr_rgba(150, 150, 150, 255);
-        table[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(120, 120, 120, 255);
-        table[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(175, 175, 175, 255);
-        table[ZR_COLOR_SELECTABLE] = zr_rgba(190, 190, 190, 255);
-        table[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(150, 150, 150, 255);
-        table[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(70, 70, 70, 255);
-        table[ZR_COLOR_SLIDER] = zr_rgba(190, 190, 190, 255);
-        table[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(80, 80, 80, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(70, 70, 70, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(60, 60, 60, 255);
-        table[ZR_COLOR_PROPERTY] = zr_rgba(175, 175, 175, 255);
-        table[ZR_COLOR_EDIT] = zr_rgba(150, 150, 150, 255);
-        table[ZR_COLOR_EDIT_CURSOR] = zr_rgba(0, 0, 0, 255);
-        table[ZR_COLOR_COMBO] = zr_rgba(175, 175, 175, 255);
-        table[ZR_COLOR_CHART] = zr_rgba(160, 160, 160, 255);
-        table[ZR_COLOR_CHART_COLOR] = zr_rgba(45, 45, 45, 255);
-        table[ZR_COLOR_CHART_COLOR_HIGHLIGHT] = zr_rgba( 255, 0, 0, 255);
-        table[ZR_COLOR_SCROLLBAR] = zr_rgba(180, 180, 180, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(140, 140, 140, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(150, 150, 150, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(160, 160, 160, 255);
-        table[ZR_COLOR_TAB_HEADER] = zr_rgba(180, 180, 180, 255);
-        zr_style_from_table(ctx, table);
-    } else if (theme == THEME_RED) {
-        table[ZR_COLOR_TEXT] = zr_rgba(190, 190, 190, 255);
-        table[ZR_COLOR_WINDOW] = zr_rgba(30, 33, 40, 215);
-        table[ZR_COLOR_HEADER] = zr_rgba(181, 45, 69, 220);
-        table[ZR_COLOR_BORDER] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_BUTTON] = zr_rgba(181, 45, 69, 255);
-        table[ZR_COLOR_BUTTON_HOVER] = zr_rgba(190, 50, 70, 255);
-        table[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(195, 55, 75, 255);
-        table[ZR_COLOR_TOGGLE] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(45, 60, 60, 255);
-        table[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(181, 45, 69, 255);
-        table[ZR_COLOR_SELECTABLE] = zr_rgba(181, 45, 69, 255);
-        table[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(181, 45, 69, 255);
-        table[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(190, 190, 190, 255);
-        table[ZR_COLOR_SLIDER] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(181, 45, 69, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(186, 50, 74, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(191, 55, 79, 255);
-        table[ZR_COLOR_PROPERTY] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_EDIT] = zr_rgba(51, 55, 67, 225);
-        table[ZR_COLOR_EDIT_CURSOR] = zr_rgba(190, 190, 190, 255);
-        table[ZR_COLOR_COMBO] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_CHART] = zr_rgba(51, 55, 67, 255);
-        table[ZR_COLOR_CHART_COLOR] = zr_rgba(170, 40, 60, 255);
-        table[ZR_COLOR_CHART_COLOR_HIGHLIGHT] = zr_rgba( 255, 0, 0, 255);
-        table[ZR_COLOR_SCROLLBAR] = zr_rgba(30, 33, 40, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(64, 84, 95, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(70, 90, 100, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(75, 95, 105, 255);
-        table[ZR_COLOR_TAB_HEADER] = zr_rgba(181, 45, 69, 220);
-        zr_style_from_table(ctx, table);
-    } else if (theme == THEME_BLUE) {
-        table[ZR_COLOR_TEXT] = zr_rgba(20, 20, 20, 255);
-        table[ZR_COLOR_WINDOW] = zr_rgba(202, 212, 214, 215);
-        table[ZR_COLOR_HEADER] = zr_rgba(137, 182, 224, 220);
-        table[ZR_COLOR_BORDER] = zr_rgba(140, 159, 173, 255);
-        table[ZR_COLOR_BUTTON] = zr_rgba(137, 182, 224, 255);
-        table[ZR_COLOR_BUTTON_HOVER] = zr_rgba(142, 187, 229, 255);
-        table[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(147, 192, 234, 255);
-        table[ZR_COLOR_TOGGLE] = zr_rgba(177, 210, 210, 255);
-        table[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(182, 215, 215, 255);
-        table[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(137, 182, 224, 255);
-        table[ZR_COLOR_SELECTABLE] = zr_rgba(147, 192, 234, 255);
-        table[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(150, 150, 150, 255);
-        table[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(70, 70, 70, 255);
-        table[ZR_COLOR_SLIDER] = zr_rgba(177, 210, 210, 255);
-        table[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(137, 182, 224, 245);
-        table[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(142, 188, 229, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(147, 193, 234, 255);
-        table[ZR_COLOR_PROPERTY] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_EDIT] = zr_rgba(210, 210, 210, 225);
-        table[ZR_COLOR_EDIT_CURSOR] = zr_rgba(20, 20, 20, 255);
-        table[ZR_COLOR_COMBO] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_CHART] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_CHART_COLOR] = zr_rgba(137, 182, 224, 255);
-        table[ZR_COLOR_CHART_COLOR_HIGHLIGHT] = zr_rgba( 255, 0, 0, 255);
-        table[ZR_COLOR_SCROLLBAR] = zr_rgba(190, 200, 200, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(64, 84, 95, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(70, 90, 100, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(75, 95, 105, 255);
-        table[ZR_COLOR_TAB_HEADER] = zr_rgba(156, 193, 220, 255);
-        zr_style_from_table(ctx, table);
-    } else if (theme == THEME_DARK) {
-        table[ZR_COLOR_TEXT] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_WINDOW] = zr_rgba(57, 67, 71, 215);
-        table[ZR_COLOR_HEADER] = zr_rgba(51, 51, 56, 220);
-        table[ZR_COLOR_BORDER] = zr_rgba(46, 46, 46, 255);
-        table[ZR_COLOR_BUTTON] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_BUTTON_HOVER] = zr_rgba(58, 93, 121, 255);
-        table[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(63, 98, 126, 255);
-        table[ZR_COLOR_TOGGLE] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(45, 53, 56, 255);
-        table[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_SELECTABLE] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_SLIDER] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(48, 83, 111, 245);
-        table[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(53, 88, 116, 255);
-        table[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(58, 93, 121, 255);
-        table[ZR_COLOR_PROPERTY] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_EDIT] = zr_rgba(50, 58, 61, 225);
-        table[ZR_COLOR_EDIT_CURSOR] = zr_rgba(210, 210, 210, 255);
-        table[ZR_COLOR_COMBO] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_CHART] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_CHART_COLOR] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_CHART_COLOR_HIGHLIGHT] = zr_rgba(255, 0, 0, 255);
-        table[ZR_COLOR_SCROLLBAR] = zr_rgba(50, 58, 61, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(48, 83, 111, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(53, 88, 116, 255);
-        table[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(58, 93, 121, 255);
-        table[ZR_COLOR_TAB_HEADER] = zr_rgba(48, 83, 111, 255);
-        zr_style_from_table(ctx, table);
-    } else {
-        zr_style_default(ctx);
-    }
-}
- 
-static int
-control_window(struct zr_context *ctx, struct demo *gui)
-{
-    struct zr_panel layout;
-    if (zr_begin(ctx, &layout, "Control", zr_rect(0, 0, 350, 520),
-        ZR_WINDOW_CLOSABLE|ZR_WINDOW_MINIMIZABLE|ZR_WINDOW_MOVABLE|
-        ZR_WINDOW_SCALABLE|ZR_WINDOW_BORDER))
-    {
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Windows", ZR_MINIMIZED)) {
-            zr_layout_row_dynamic(ctx, 25, 2);
-            gui->show_simple = !zr_window_is_closed(ctx, "Show");
-            gui->show_node = !zr_window_is_closed(ctx, "Node Editor");
-            gui->show_demo = !zr_window_is_closed(ctx, "Demo");
-#ifndef DEMO_DO_NOT_DRAW_IMAGES
-            gui->show_filex = !zr_window_is_closed(ctx, "File Browser");
-            gui->show_grid = !zr_window_is_closed(ctx, "Grid Demo");
-            gui->show_basic = !zr_window_is_closed(ctx, "Basic Demo");
-            gui->show_button = !zr_window_is_closed(ctx, "Button Demo");
-#endif
-
-            if (zr_checkbox_label(ctx, "Show", &gui->show_simple) && !gui->show_simple)
-                zr_window_close(ctx, "Show");
-            if (zr_checkbox_label(ctx, "Demo", &gui->show_demo) && !gui->show_demo)
-                zr_window_close(ctx, "Demo");
-            if (zr_checkbox_label(ctx, "Node Editor", &gui->show_node) && !gui->show_node)
-                zr_window_close(ctx, "Node Editor");
-#ifndef DEMO_DO_NOT_DRAW_IMAGES
-            if (zr_checkbox_label(ctx, "Grid", &gui->show_grid) && !gui->show_grid)
-                zr_window_close(ctx, "Grid Demo");
-            if (zr_checkbox_label(ctx, "Basic", &gui->show_basic) && !gui->show_basic)
-                zr_window_close(ctx, "Basic Demo");
-            if (zr_checkbox_label(ctx, "Button", &gui->show_button) && !gui->show_button)
-                zr_window_close(ctx, "Button Demo");
-            if (zr_checkbox_label(ctx, "Filex", &gui->show_filex) && !gui->show_filex)
-                zr_window_close(ctx, "File Browser");
-#endif
-            zr_layout_pop(ctx);
-        }
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Metrics", ZR_MINIMIZED)) {
-            zr_layout_row_dynamic(ctx, 20, 2);
-            zr_label(ctx,"Total:", ZR_TEXT_LEFT);
-            zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", gui->status.size);
-            zr_label(ctx,"Used:", ZR_TEXT_LEFT);
-            zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", gui->status.allocated);
-            zr_label(ctx,"Required:", ZR_TEXT_LEFT);
-            zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", gui->status.needed);
-            zr_label(ctx,"Calls:", ZR_TEXT_LEFT);
-            zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", gui->status.calls);
-            zr_layout_pop(ctx);
-        }
-        if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Color", ZR_MINIMIZED))
-        {
-            struct zr_panel combo;
-            enum theme old = gui->theme;
-            static const char *themes[] = {"Black", "White", "Red", "Blue", "Dark", "Grey"};
-
-            zr_layout_row_dynamic(ctx,  25, 2);
-            zr_label(ctx, "THEME:", ZR_TEXT_LEFT);
-            if (zr_combo_begin_label(ctx, &combo, themes[gui->theme], 300)) {
-                zr_layout_row_dynamic(ctx, 25, 1);
-                gui->theme = zr_combo_item_label(ctx, themes[THEME_BLACK], ZR_TEXT_CENTERED) ? THEME_BLACK : gui->theme;
-                gui->theme = zr_combo_item_label(ctx, themes[THEME_WHITE], ZR_TEXT_CENTERED) ? THEME_WHITE : gui->theme;
-                gui->theme = zr_combo_item_label(ctx, themes[THEME_RED], ZR_TEXT_CENTERED) ? THEME_RED : gui->theme;
-                gui->theme = zr_combo_item_label(ctx, themes[THEME_BLUE], ZR_TEXT_CENTERED) ? THEME_BLUE : gui->theme;
-                gui->theme = zr_combo_item_label(ctx, themes[THEME_DARK], ZR_TEXT_CENTERED) ? THEME_DARK : gui->theme;
-                if (old != gui->theme) set_style(ctx, gui->theme);
-                zr_combo_end(ctx);
-            }
-            zr_layout_pop(ctx);
-        }
-    }
-    zr_end(ctx);
-    return !zr_window_is_closed(ctx, "Control");
-}
-
-
-/* ===============================================================
- *
- *                          DEMO ENTRY
- *
- * ===============================================================*/
-static int
-run_demo(struct demo *gui)
-{
-    int ret = 1;
-    static int init = 0;
-    static struct node_editor nodedit;
-    static struct file_browser filex;
-    struct zr_context *ctx = &gui->ctx;
-    struct zr_style *style = &ctx->style;
-
-    ctx->style.font.height = 14;
-    if (!init) {
-        init = 1;
-        gui->show_demo = 0;
-        gui->show_node = 0;
-        gui->show_simple = 0;
-
-        gui->show_grid = 0;
-        gui->show_basic = 0;
-        gui->show_button = 0;
-
-        memset(&nodedit, 0, sizeof(nodedit));
-        node_editor_init(&nodedit);
-#ifndef DEMO_DO_NOT_DRAW_IMAGES
-#ifdef __unix__
-        file_browser_init(&filex, &gui->icons);
-#endif
-#endif
-    }
-
-    ret = control_window(ctx, gui);
-    if (gui->show_demo)
-        demo_window(gui, ctx);
-    if (gui->show_simple)
-        simple_window(ctx);
-    if (gui->show_node)
-        node_editor_demo(ctx, &nodedit);
-
-#ifndef DEMO_DO_NOT_DRAW_IMAGES
-#ifdef __unix__
-    if (gui->show_filex)
-        file_browser_run(&filex, ctx);
-    if (!ret) file_browser_free(&filex);
-#endif
-    if (gui->show_grid)
-        grid_demo(ctx);
-    if (gui->show_button)
-        button_demo(ctx, &gui->icons);
-    if (gui->show_basic)
-        basic_demo(ctx, &gui->icons);
-#endif
-    zr_buffer_info(&gui->status, &gui->ctx.memory);
-    return ret;
-}
-

+ 1 - 1
demo/glfw/Makefile

@@ -8,7 +8,7 @@ DCC = gcc
 # Flags
 CFLAGS = -std=c99 -pedantic -O2
 
-SRC = ../../zahnrad.c glfw.c
+SRC = main.c
 OBJ = $(SRC:.c=.o)
 
 ifeq ($(OS),Windows_NT)

+ 0 - 591
demo/glfw/glfw.c

@@ -1,591 +0,0 @@
-/*
-    Copyright (c) 2016 Micha Mettke
-
-    This software is provided 'as-is', without any express or implied
-    warranty.  In no event will the authors be held liable for any damages
-    arising from the use of this software.
-
-    Permission is granted to anyone to use this software for any purpose,
-    including commercial applications, and to alter it and redistribute it
-    freely, subject to the following restrictions:
-
-    1.  The origin of this software must not be misrepresented; you must not
-        claim that you wrote the original software. If you use this software
-        in a product, an acknowledgment in the product documentation would be
-        appreciated but is not required.
-    2.  Altered source versions must be plainly marked as such, and must not be
-        misrepresented as being the original software.
-    3.  This notice may not be removed or altered from any source distribution.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include <math.h>
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#include <GLFW/glfw3.h>
-
-/* macros */
-#define MAX_VERTEX_MEMORY 512 * 1024
-#define MAX_ELEMENT_MEMORY 128 * 1024
-
-#include "../../zahnrad.h"
-#include "../demo.c"
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#pragma clang diagnostic ignored "-Wbad-function-cast"
-#pragma clang diagnostic ignored "-Wcast-qual"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
-#pragma clang diagnostic ignored "-Wunused-function"
-#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#pragma GCC diagnostic ignored "-Wconversion"
-#pragma GCC diagnostic ignored "-Wbad-function-cast"
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
-#pragma GCC diagnostic ignored "-Wtype-limits"
-#pragma GCC diagnostic ignored "-Wswitch-default"
-#pragma GCC diagnostic ignored "-Wunused-function"
-#elif _MSC_VER
-#pragma warning (push)
-#pragma warning (disable: 4456)
-#endif
-
-#define STB_IMAGE_IMPLEMENTATION
-#include "../stb_image.h"
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic pop
-#elif _MSC_VER
-#pragma warning (pop)
-#endif
-
-static int mouse_pos_x = 0;
-static int mouse_pos_y = 0;
-static struct demo gui;
-
-/* ==============================================================
- *
- *                      Utility
- *
- * ===============================================================*/
-static void
-die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fputs("\n", stderr);
-    exit(EXIT_FAILURE);
-}
-
-static char*
-file_load(const char* path, size_t* siz)
-{
-    char *buf;
-    FILE *fd = fopen(path, "rb");
-    if (!fd) die("Failed to open file: %s\n", path);
-    fseek(fd, 0, SEEK_END);
-    *siz = (size_t)ftell(fd);
-    fseek(fd, 0, SEEK_SET);
-    buf = (char*)calloc(*siz, 1);
-    fread(buf, *siz, 1, fd);
-    fclose(fd);
-    return buf;
-}
-
-static struct zr_image
-icon_load(const char *filename)
-{
-    int x,y,n;
-    GLuint tex;
-    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
-    if (!data) die("[SDL]: failed to load image: %s", filename);
-
-    glGenTextures(1, &tex);
-    glBindTexture(GL_TEXTURE_2D, tex);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-    glGenerateMipmap(GL_TEXTURE_2D);
-    stbi_image_free(data);
-    return zr_image_id((int)tex);
-}
-
-struct device {
-    struct zr_buffer cmds;
-    struct zr_draw_null_texture null;
-    GLuint vbo, vao, ebo;
-
-    GLuint prog;
-    GLuint vert_shdr;
-    GLuint frag_shdr;
-
-    GLint attrib_pos;
-    GLint attrib_uv;
-    GLint attrib_col;
-
-    GLint uniform_tex;
-    GLint uniform_proj;
-    GLuint font_tex;
-};
-
-static void
-device_init(struct device *dev)
-{
-    GLint status;
-    static const GLchar *vertex_shader =
-        "#version 300 es\n"
-        "uniform mat4 ProjMtx;\n"
-        "in vec2 Position;\n"
-        "in vec2 TexCoord;\n"
-        "in vec4 Color;\n"
-        "out vec2 Frag_UV;\n"
-        "out vec4 Frag_Color;\n"
-        "void main() {\n"
-        "   Frag_UV = TexCoord;\n"
-        "   Frag_Color = Color;\n"
-        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
-        "}\n";
-    static const GLchar *fragment_shader =
-        "#version 300 es\n"
-        "precision mediump float;\n"
-        "uniform sampler2D Texture;\n"
-        "in vec2 Frag_UV;\n"
-        "in vec4 Frag_Color;\n"
-        "out vec4 Out_Color;\n"
-        "void main(){\n"
-        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
-        "}\n";
-
-    dev->prog = glCreateProgram();
-    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
-    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
-    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
-    glCompileShader(dev->vert_shdr);
-    glCompileShader(dev->frag_shdr);
-    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glAttachShader(dev->prog, dev->vert_shdr);
-    glAttachShader(dev->prog, dev->frag_shdr);
-    glLinkProgram(dev->prog);
-    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
-    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
-    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
-    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
-    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
-
-    {
-        /* buffer setup */
-        GLsizei vs = sizeof(struct zr_draw_vertex);
-        size_t vp = offsetof(struct zr_draw_vertex, position);
-        size_t vt = offsetof(struct zr_draw_vertex, uv);
-        size_t vc = offsetof(struct zr_draw_vertex, col);
-
-        glGenBuffers(1, &dev->vbo);
-        glGenBuffers(1, &dev->ebo);
-        glGenVertexArrays(1, &dev->vao);
-
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
-        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
-        glEnableVertexAttribArray((GLuint)dev->attrib_col);
-
-        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
-        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
-        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
-    }
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-}
-
-static void
-device_upload_atlas(struct device *dev, const void *image, int width, int height)
-{
-    glGenTextures(1, &dev->font_tex);
-    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, image);
-}
-
-static void
-device_shutdown(struct device *dev)
-{
-    glDetachShader(dev->prog, dev->vert_shdr);
-    glDetachShader(dev->prog, dev->frag_shdr);
-    glDeleteShader(dev->vert_shdr);
-    glDeleteShader(dev->frag_shdr);
-    glDeleteProgram(dev->prog);
-    glDeleteTextures(1, &dev->font_tex);
-    glDeleteBuffers(1, &dev->vbo);
-    glDeleteBuffers(1, &dev->ebo);
-}
-
-static void
-device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
-    enum zr_anti_aliasing AA)
-{
-    GLint last_prog, last_tex;
-    GLint last_ebo, last_vbo, last_vao;
-    GLfloat ortho[4][4] = {
-        {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},
-    };
-    ortho[0][0] /= (GLfloat)width;
-    ortho[1][1] /= (GLfloat)height;
-
-    /* save previous opengl state */
-    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
-    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
-    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
-    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
-
-    /* setup global state */
-    glEnable(GL_BLEND);
-    glBlendEquation(GL_FUNC_ADD);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-    glEnable(GL_SCISSOR_TEST);
-    glActiveTexture(GL_TEXTURE0);
-
-    /* setup program */
-    glUseProgram(dev->prog);
-    glUniform1i(dev->uniform_tex, 0);
-    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
-
-    {
-        /* convert from command queue into draw list and draw to screen */
-        const struct zr_draw_command *cmd;
-        void *vertices, *elements;
-        const zr_draw_index *offset = NULL;
-
-        /* allocate vertex and element buffer */
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
-
-        /* load draw vertices & elements directly into vertex + element buffer */
-        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
-        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
-        {
-            struct zr_buffer vbuf, ebuf;
-
-            /* fill converting configuration */
-            struct zr_convert_config config;
-            memset(&config, 0, sizeof(config));
-            config.global_alpha = 1.0f;
-            config.shape_AA = AA;
-            config.line_AA = AA;
-            config.circle_segment_count = 22;
-            config.curve_segment_count = 22;
-            config.arc_segment_count = 22;
-            config.null = dev->null;
-
-            /* setup buffers to load vertices and elements */
-            zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
-            zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
-            zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
-        }
-        glUnmapBuffer(GL_ARRAY_BUFFER);
-        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-
-        /* iterate over and execute each draw command */
-        zr_draw_foreach(cmd, ctx, &dev->cmds) {
-            if (!cmd->elem_count) continue;
-            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-            glScissor((GLint)cmd->clip_rect.x,
-                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
-                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
-            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-            offset += cmd->elem_count;
-        }
-        zr_clear(ctx);
-    }
-
-    /* restore old state */
-    glUseProgram((GLuint)last_prog);
-    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
-    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
-    glBindVertexArray((GLuint)last_vao);
-    glDisable(GL_SCISSOR_TEST);
-}
-
-static void
-error_callback(int error, const char *description)
-{
-    fprintf(stderr, "Error %d: %s\n", error, description);
-}
-
-static void
-input_key(GLFWwindow *window, int key, int scancode, int action, int mods)
-{
-    int down = action == GLFW_PRESS;
-    UNUSED(window);
-    UNUSED(scancode);
-    if (key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_SHIFT)
-        zr_input_key(&gui.ctx, ZR_KEY_SHIFT, down);
-    else if (key == GLFW_KEY_TAB)
-        zr_input_key(&gui.ctx, ZR_KEY_TAB, down);
-    else if (key == GLFW_KEY_DELETE)
-        zr_input_key(&gui.ctx, ZR_KEY_DEL, down);
-    else if (key == GLFW_KEY_ENTER)
-        zr_input_key(&gui.ctx, ZR_KEY_ENTER, down);
-    else if (key == GLFW_KEY_BACKSPACE)
-        zr_input_key(&gui.ctx, ZR_KEY_BACKSPACE, down);
-    else if (key == GLFW_KEY_LEFT)
-        zr_input_key(&gui.ctx, ZR_KEY_LEFT, down);
-    else if (key == GLFW_KEY_RIGHT)
-        zr_input_key(&gui.ctx, ZR_KEY_RIGHT, down);
-    else if (key == GLFW_KEY_C)
-        zr_input_key(&gui.ctx, ZR_KEY_COPY, down && (mods & GLFW_MOD_CONTROL));
-    else if (key == GLFW_KEY_V)
-        zr_input_key(&gui.ctx, ZR_KEY_PASTE, down && (mods & GLFW_MOD_CONTROL));
-    else if (key == GLFW_KEY_X)
-        zr_input_key(&gui.ctx, ZR_KEY_CUT, down && (mods & GLFW_MOD_CONTROL));
-}
-
-static void
-input_motion(GLFWwindow *window, double xpos, double ypos)
-{
-    const int x = (int)xpos;
-    const int y = (int)ypos;
-    UNUSED(window);
-    mouse_pos_x = x;
-    mouse_pos_y = y;
-    zr_input_motion(&gui.ctx, x, y);
-}
-
-static void
-input_button(GLFWwindow *window, int button, int action, int mods)
-{
-    int x = mouse_pos_x;
-    int y = mouse_pos_y;
-    UNUSED(window);
-    UNUSED(mods);
-    if (button == 0)
-        zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, x, y, action == GLFW_PRESS);
-    if (button == 1)
-        zr_input_button(&gui.ctx, ZR_BUTTON_RIGHT, x, y, action == GLFW_PRESS);
-    if (button == 2)
-        zr_input_button(&gui.ctx, ZR_BUTTON_MIDDLE, x, y, action == GLFW_PRESS);
-}
-
-static void
-input_text(GLFWwindow *window, unsigned int codepoint)
-{
-    UNUSED(window);
-    zr_input_unicode(&gui.ctx, codepoint);
-}
-
-static void
-input_scroll(GLFWwindow *window, double xoffset, double yoffset)
-{
-    UNUSED(window);
-    UNUSED(xoffset);
-    zr_input_scroll(&gui.ctx, (float)yoffset);
-}
-
-int
-main(int argc, char *argv[])
-{
-    /* Platform */
-    int i;
-    static GLFWwindow *win;
-    const char *font_path;
-    int width = 0, height = 0;
-    int running = 1;
-
-    /* GUI */
-    struct device device;
-    struct zr_font *font;
-    struct zr_font_atlas atlas;
-    font_path = (argc > 1) ? argv[1]: 0;
-
-    glfwSetErrorCallback(error_callback);
-    if (!glfwInit()) {
-        fprintf(stdout, "[GFLW] failed to init!\n");
-        return 1;
-    }
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-#ifdef __APPLE__
-    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
-#endif
-    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
-    glfwMakeContextCurrent(win);
-
-    glfwSetCursorPosCallback(win, input_motion);
-    glfwSetMouseButtonCallback(win, input_button);
-    glfwSetKeyCallback(win, input_key);
-    glfwSetCharCallback(win, input_text);
-    glfwSetScrollCallback(win, input_scroll);
-
-    /* OpenGL */
-    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
-    glewExperimental = 1;
-    if (glewInit() != GLEW_OK)
-        die("Failed to setup GLEW\n");
-
-    device_init(&device);
-    {
-        /* Font */
-        const void *image;
-        int w, h;
-
-        zr_font_atlas_init_default(&atlas);
-        zr_font_atlas_begin(&atlas);
-        if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
-        else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
-        image = zr_font_atlas_bake(&atlas, &w, &h, ZR_FONT_ATLAS_RGBA32);
-        device_upload_atlas(&device, image, w, h);
-        zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
-
-        /* GUI */
-        memset(&gui, 0, sizeof(gui));
-        zr_buffer_init_default(&device.cmds);
-        zr_init_default(&gui.ctx, &font->handle);
-    }
-
-    /* icons */
-    glEnable(GL_TEXTURE_2D);
-    gui.icons.unchecked = icon_load("../../icon/unchecked.png");
-    gui.icons.checked = icon_load("../../icon/checked.png");
-    gui.icons.rocket = icon_load("../../icon/rocket.png");
-    gui.icons.cloud = icon_load("../../icon/cloud.png");
-    gui.icons.pen = icon_load("../../icon/pen.png");
-    gui.icons.play = icon_load("../../icon/play.png");
-    gui.icons.pause = icon_load("../../icon/pause.png");
-    gui.icons.stop = icon_load("../../icon/stop.png");
-    gui.icons.next =  icon_load("../../icon/next.png");
-    gui.icons.prev =  icon_load("../../icon/prev.png");
-    gui.icons.tools = icon_load("../../icon/tools.png");
-    gui.icons.dir = icon_load("../../icon/directory.png");
-    gui.icons.copy = icon_load("../../icon/copy.png");
-    gui.icons.convert = icon_load("../../icon/export.png");
-    gui.icons.del = icon_load("../../icon/delete.png");
-    gui.icons.edit = icon_load("../../icon/edit.png");
-    gui.icons.menu[0] = icon_load("../../icon/home.png");
-    gui.icons.menu[1] = icon_load("../../icon/phone.png");
-    gui.icons.menu[2] = icon_load("../../icon/plane.png");
-    gui.icons.menu[3] = icon_load("../../icon/wifi.png");
-    gui.icons.menu[4] = icon_load("../../icon/settings.png");
-    gui.icons.menu[5] = icon_load("../../icon/volume.png");
-
-    gui.icons.home = icon_load("../../icon/home.png");
-    gui.icons.directory = icon_load("../../icon/directory.png");
-    gui.icons.computer = icon_load("../../icon/computer.png");
-    gui.icons.desktop = icon_load("../../icon/desktop.png");
-    gui.icons.default_file = icon_load("../../icon/default.png");
-    gui.icons.text_file = icon_load("../../icon/text.png");
-    gui.icons.music_file = icon_load("../../icon/music.png");
-    gui.icons.font_file =  icon_load("../../icon/font.png");
-    gui.icons.img_file = icon_load("../../icon/img.png");
-    gui.icons.movie_file = icon_load("../../icon/movie.png");
-
-    for (i = 0; i < 9; ++i) {
-        char buffer[256];
-        sprintf(buffer, "../../images/image%d.png", (i+1));
-        gui.icons.images[i] = icon_load(buffer);
-    }
-
-    while (!glfwWindowShouldClose(win) && running) {
-        /* Input */
-        zr_input_begin(&gui.ctx);
-        glfwPollEvents();
-        zr_input_end(&gui.ctx);
-
-        /* GUI */
-        glfwGetWindowSize(win, &width, &height);
-        running = run_demo(&gui);
-
-        /* Draw */
-        glViewport(0, 0, width, height);
-        glClear(GL_COLOR_BUFFER_BIT);
-        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
-        device_draw(&device, &gui.ctx, width, height, ZR_ANTI_ALIASING_ON);
-        glfwSwapBuffers(win);
-    }
-
-    /* Cleanup */
-    glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
-
-    glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
-
-    for (i = 0; i < 9; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
-    for (i = 0; i < 6; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
-
-    zr_font_atlas_clear(&atlas);
-    zr_free(&gui.ctx);
-    zr_buffer_free(&device.cmds);
-    device_shutdown(&device);
-    glfwTerminate();
-    return 0;
-}
-

+ 139 - 0
demo/glfw/main.c

@@ -0,0 +1,139 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GLFW/glfw3.h>
+
+/* these defines are both needed for the header
+ * and source file. So if you split them remember
+ * to copy them as well. */
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#include "nuklear_glfw.h"
+#include "nuklear_glfw.c"
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+static void error_callback(int e, const char *d){
+    printf("Error %d: %s\n", e, d);
+}
+
+int main(void)
+{
+    /* Platform */
+    static GLFWwindow *win;
+    int width = 0, height = 0;
+    struct nk_context *ctx;
+    struct nk_color background;
+
+    /* GLFW */
+    glfwSetErrorCallback(error_callback);
+    if (!glfwInit()) {
+        fprintf(stdout, "[GFLW] failed to init!\n");
+        exit(1);
+    }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwMakeContextCurrent(win);
+
+    /* OpenGL */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    {struct nk_font_atlas *atlas;
+    nk_glfw3_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-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_glfw3_font_stash_end();
+    /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+    background = nk_rgb(28,48,62);
+    while (!glfwWindowShouldClose(win))
+    {
+        /* Input */
+        glfwPollEvents();
+        nk_glfw3_new_frame();
+
+        /* GUI */
+        {struct nk_panel layout;
+        if (nk_begin(ctx, &layout, "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", NK_BUTTON_DEFAULT))
+                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, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            {struct nk_panel combo;
+            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, &combo, background, 400)) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }}
+        }
+        nk_end(ctx);}
+
+        /* Draw */
+        {float bg[4];
+        nk_color_fv(bg, background);
+        glfwGetWindowSize(win, &width, &height);
+        glViewport(0, 0, width, height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(bg[0], bg[1], bg[2], bg[3]);
+        nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+        glfwSwapBuffers(win);}
+    }
+    nk_glfw3_shutdown();
+    glfwTerminate();
+    return 0;
+}
+

+ 374 - 0
demo/glfw/nuklear_glfw.c

@@ -0,0 +1,374 @@
+#include <string.h>
+
+#define NK_IMPLEMENTATION
+#include "nuklear_glfw.h"
+#include "../../nuklear.h"
+
+#define NK_GLFW_TEXT_MAX 256
+struct nk_glfw_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+static struct nk_glfw {
+    GLFWwindow *win;
+    struct nk_glfw_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    unsigned int text[NK_GLFW_TEXT_MAX];
+    int text_len;
+    float scroll;
+} glfw;
+
+NK_API void
+nk_glfw3_device_create(void)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    struct nk_glfw_device *dev = &glfw.ogl;
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+NK_INTERN void
+nk_glfw3_device_upload_atlas(const void *image, int width, int height)
+{
+    struct nk_glfw_device *dev = &glfw.ogl;
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_glfw3_device_destroy(void)
+{
+    struct nk_glfw_device *dev = &glfw.ogl;
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+    struct nk_glfw_device *dev = &glfw.ogl;
+    int width, height;
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    glfwGetWindowSize(glfw.win, &width, &height);
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
+            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(&glfw.ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+NK_API void
+nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
+{
+    (void)win;
+    if (glfw.text_len < NK_GLFW_TEXT_MAX)
+        glfw.text[glfw.text_len++] = codepoint;
+}
+
+NK_API void
+nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
+{
+    (void)win; (void)xoff;
+    glfw.scroll += (float)yoff;
+}
+
+static void
+nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    const char *text = glfwGetClipboardString(glfw.win);
+    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+    (void)usr;
+}
+
+static void
+nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+    char *str = 0;
+    (void)usr;
+    if (!len) return;
+    str = malloc((size_t)len+1);
+    if (!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+    glfwSetClipboardString(glfw.win, str);
+    free(str);
+}
+
+NK_API struct nk_context*
+nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
+{
+    glfw.win = win;
+    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
+        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
+        glfwSetCharCallback(win, nk_glfw3_char_callback);
+    }
+
+    nk_init_default(&glfw.ctx, 0);
+    glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
+    glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
+    glfw.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_glfw3_device_create();
+    return &glfw.ctx;
+}
+
+NK_API void
+nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&glfw.atlas);
+    nk_font_atlas_begin(&glfw.atlas);
+    *atlas = &glfw.atlas;
+}
+
+NK_API void
+nk_glfw3_font_stash_end(void)
+{
+    const void *image; int w, h;
+    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_glfw3_device_upload_atlas(image, w, h);
+    nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null);
+    if (glfw.atlas.default_font)
+        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);
+}
+
+NK_API void
+nk_glfw3_new_frame(void)
+{
+    int i;
+    double x, y;
+    struct nk_context *ctx = &glfw.ctx;
+    struct GLFWwindow *win = glfw.win;
+    nk_input_begin(ctx);
+    for (i = 0; i < glfw.text_len; ++i)
+        nk_input_unicode(ctx, glfw.text[i]);
+
+    nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
+                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
+
+    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
+        nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+    } else {
+        nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(ctx, NK_KEY_COPY, 0);
+        nk_input_key(ctx, NK_KEY_PASTE, 0);
+        nk_input_key(ctx, NK_KEY_CUT, 0);
+        nk_input_key(ctx, NK_KEY_SHIFT, 0);
+    }
+
+    glfwGetCursorPos(win, &x, &y);
+    nk_input_motion(ctx, (int)x, (int)y);
+    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+    nk_input_scroll(ctx, glfw.scroll);
+    nk_input_end(&glfw.ctx);
+
+    glfw.text_len = 0;
+    glfw.scroll = 0;
+}
+
+NK_API
+void nk_glfw3_shutdown(void)
+{
+    nk_font_atlas_clear(&glfw.atlas);
+    nk_free(&glfw.ctx);
+    nk_glfw3_device_destroy();
+}
+

+ 23 - 0
demo/glfw/nuklear_glfw.h

@@ -0,0 +1,23 @@
+#ifndef NK_GLFW_H_
+#define NK_GLFW_H_
+
+#include "../../nuklear.h"
+
+#include <GLFW/glfw3.h>
+
+enum nk_glfw_init_state{NK_GLFW3_DEFAULT=0, NK_GLFW3_INSTALL_CALLBACKS};
+NK_API struct nk_context *nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);
+NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_glfw3_font_stash_end(void);
+
+NK_API void nk_glfw3_new_frame(void);
+NK_API void nk_glfw3_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_glfw3_shutdown(void);
+
+NK_API void nk_glfw3_device_destroy(void);
+NK_API void nk_glfw3_device_create(void);
+
+NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
+NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+
+#endif

+ 0 - 26
demo/linuxgl/Makefile

@@ -1,26 +0,0 @@
-# Install
-BIN = zahnrad
-
-# Compiler
-CC = clang
-DCC = gcc
-
-# Flags
-CFLAGS = -std=c99 -pedantic -O2
-
-SRC = linuxgl.c ../../zahnrad.c
-OBJ = $(SRC:.c=.o)
-
-# Modes
-.PHONY: gcc
-gcc: CC = gcc
-gcc: $(BIN)
-
-.PHONY: clang
-clang: CC = clang
-clang: $(BIN)
-
-$(BIN):
-	@mkdir -p bin
-	rm -f bin/$(BIN) $(OBJS)
-	$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU

+ 0 - 963
demo/linuxgl/linuxgl.c

@@ -1,963 +0,0 @@
-/*
-    Copyright (c) 2016 Micha Mettke
-
-    This software is provided 'as-is', without any express or implied
-    warranty.  In no event will the authors be held liable for any damages
-    arising from the use of this software.
-
-    Permission is granted to anyone to use this software for any purpose,
-    including commercial applications, and to alter it and redistribute it
-    freely, subject to the following restrictions:
-
-    1.  The origin of this software must not be misrepresented; you must not
-        claim that you wrote the original software. If you use this software
-        in a product, an acknowledgment in the product documentation would be
-        appreciated but is not required.
-    2.  Altered source versions must be plainly marked as such, and must not be
-        misrepresented as being the original software.
-    3.  This notice may not be removed or altered from any source distribution.
-*/
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <math.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include <GL/gl.h>
-#include <GL/glx.h>
-#include <GL/glext.h>
-#include <GL/glxext.h>
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#include "../../zahnrad.h"
-#include "../demo.c"
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#pragma clang diagnostic ignored "-Wbad-function-cast"
-#pragma clang diagnostic ignored "-Wcast-qual"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
-#pragma clang diagnostic ignored "-Wunused-function"
-#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#pragma GCC diagnostic ignored "-Wconversion"
-#pragma GCC diagnostic ignored "-Wbad-function-cast"
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
-#pragma GCC diagnostic ignored "-Wtype-limits"
-#pragma GCC diagnostic ignored "-Wswitch-default"
-#pragma GCC diagnostic ignored "-Wunused-function"
-#elif _MSC_VER
-#pragma warning (push)
-#pragma warning (disable: 4456)
-#endif
-
-#define STB_IMAGE_IMPLEMENTATION
-#include "../stb_image.h"
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic pop
-#elif _MSC_VER
-#pragma warning (pop)
-#endif
-
-/* prefered OpenGL version */
-#define OGL_MAJOR_VERSION 3
-#define OGL_MINOR_VERSION 0
-
-#define MAX_VERTEX_MEMORY 512 * 1024
-#define MAX_ELEMENT_MEMORY 128 * 1024
-#define UNUSED(a)   ((void)(a))
-
-typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
-/* GL_ARB_vertex_buffer_object */
-typedef void(*qglGenBuffers)(GLsizei, GLuint*);
-typedef void(*qglBindBuffer)(GLenum, GLuint);
-typedef void(*qglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
-typedef void(*qglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);
-typedef void*(*qglMapBuffer)(GLenum, GLenum);
-typedef GLboolean(*qglUnmapBuffer)(GLenum);
-typedef void(*qglDeleteBuffers)(GLsizei, GLuint*);
-/* GL_ARB_vertex_array_object */
-typedef void (*qglGenVertexArrays)(GLsizei, GLuint*);
-typedef void (*qglBindVertexArray)(GLuint);
-typedef void (*qglDeleteVertexArrays)(GLsizei, const GLuint*);
-/* GL_ARB_vertex_program / GL_ARB_fragment_program */
-typedef void(*qglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
-typedef void(*qglEnableVertexAttribArray)(GLuint);
-typedef void(*qglDisableVertexAttribArray)(GLuint);
-/* GL_ARB_framebuffer_object */
-typedef void(*qglGenerateMipmap)(GLenum target);
-/* GLSL/OpenGL 2.0 core */
-typedef GLuint(*qglCreateShader)(GLenum);
-typedef void(*qglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);
-typedef void(*qglCompileShader)(GLuint);
-typedef void(*qglGetShaderiv)(GLuint, GLenum, GLint*);
-typedef void(*qglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
-typedef void(*qglDeleteShader)(GLuint);
-typedef GLuint(*qglCreateProgram)(void);
-typedef void(*qglAttachShader)(GLuint, GLuint);
-typedef void(*qglDetachShader)(GLuint, GLuint);
-typedef void(*qglLinkProgram)(GLuint);
-typedef void(*qglUseProgram)(GLuint);
-typedef void(*qglGetProgramiv)(GLuint, GLenum, GLint*);
-typedef void(*qglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
-typedef void(*qglDeleteProgram)(GLuint);
-typedef GLint(*qglGetUniformLocation)(GLuint, const GLchar*);
-typedef GLint(*qglGetAttribLocation)(GLuint, const GLchar*);
-typedef void(*qglUniform1i)(GLint, GLint);
-typedef void(*qglUniform1f)(GLint, GLfloat);
-typedef void(*qglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);
-typedef void(*qglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);
-
-static qglGenBuffers glGenBuffers;
-static qglBindBuffer glBindBuffer;
-static qglBufferData glBufferData;
-static qglBufferSubData glBufferSubData;
-static qglMapBuffer glMapBuffer;
-static qglUnmapBuffer glUnmapBuffer;
-static qglDeleteBuffers glDeleteBuffers;
-static qglGenVertexArrays glGenVertexArrays;
-static qglBindVertexArray glBindVertexArray;
-static qglDeleteVertexArrays glDeleteVertexArrays;
-static qglVertexAttribPointer glVertexAttribPointer;
-static qglEnableVertexAttribArray glEnableVertexAttribArray;
-static qglDisableVertexAttribArray glDisableVertexAttribArray;
-static qglGenerateMipmap glGenerateMipmap;
-static qglCreateShader glCreateShader;
-static qglShaderSource glShaderSource;
-static qglCompileShader glCompileShader;
-static qglGetShaderiv glGetShaderiv;
-static qglGetShaderInfoLog glGetShaderInfoLog;
-static qglDeleteShader glDeleteShader;
-static qglCreateProgram glCreateProgram;
-static qglAttachShader glAttachShader;
-static qglDetachShader glDetachShader;
-static qglLinkProgram glLinkProgram;
-static qglUseProgram glUseProgram;
-static qglGetProgramiv glGetProgramiv;
-static qglGetProgramInfoLog glGetProgramInfoLog;
-static qglDeleteProgram glDeleteProgram;
-static qglGetUniformLocation glGetUniformLocation;
-static qglGetAttribLocation glGetAttribLocation;
-static qglUniform1i glUniform1i;
-static qglUniform1f glUniform1f;
-static qglUniformMatrix3fv glUniformMatrix3fv;
-static qglUniformMatrix4fv glUniformMatrix4fv;
-
-enum graphics_card_vendors {
-    VENDOR_UNKNOWN,
-    VENDOR_NVIDIA,
-    VENDOR_AMD,
-    VENDOR_INTEL
-};
-
-struct opengl {
-    /* context */
-    GLXContext ctx;
-    glxCreateContext create_context;
-    /* info */
-    const char *vendor_str;
-    const char *version_str;
-    const char *extensions_str;
-    const char *renderer_str;
-    const char *glsl_version_str;
-    enum graphics_card_vendors vendor;
-    /* version */
-    float version;
-    int major_version;
-    int minor_version;
-    /* extensions */
-    int glsl_available;
-    int vertex_buffer_obj_available;
-    int vertex_array_obj_available;
-    int map_buffer_range_available;
-    int fragment_program_available;
-    int frame_buffer_object_available;
-};
-
-struct device {
-    GLuint vbo, vao, ebo;
-    GLuint prog;
-    GLuint vert_shdr;
-    GLuint frag_shdr;
-    GLint attrib_pos;
-    GLint attrib_uv;
-    GLint attrib_col;
-    GLint uniform_tex;
-    GLint uniform_proj;
-    GLuint font_tex;
-    struct zr_draw_null_texture null;
-    struct zr_buffer cmds;
-};
-
-struct XWindow {
-    Display *dpy;
-    Window win;
-    XVisualInfo *vis;
-    Colormap cmap;
-    XSetWindowAttributes swa;
-    XWindowAttributes attr;
-    GLXFBConfig fbc;
-    int width, height;
-};
-static int gl_err = FALSE;
-
-static void
-die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fputs("\n", stderr);
-    exit(EXIT_FAILURE);
-}
-
-static struct zr_image
-icon_load(const char *filename)
-{
-    int x,y,n;
-    GLuint tex;
-    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
-    if (!data) die("[SDL]: failed to load image: %s", filename);
-
-    glGenTextures(1, &tex);
-    glBindTexture(GL_TEXTURE_2D, tex);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-    glGenerateMipmap(GL_TEXTURE_2D);
-    stbi_image_free(data);
-    return zr_image_id((int)tex);
-}
-
-static int
-gl_check_extension(struct opengl *GL, const char *ext)
-{
-    const char *start, *where, *term;
-    where = strchr(ext, ' ');
-    if (where || *ext == '\0')
-        return FALSE;
-
-    for (start = GL->extensions_str;;) {
-        where = strstr((const char*)start, ext);
-        if (!where) break;
-        term = where + strlen(ext);
-        if (where == start || *(where - 1) == ' ') {
-            if (*term == ' ' || *term == '\0')
-                return TRUE;
-        }
-        start = term;
-    }
-    return FALSE;
-}
-
-#define GL_EXT(name) (q##name)gl_ext(#name)
-static __GLXextFuncPtr
-gl_ext(const char *name)
-{
-    __GLXextFuncPtr func;
-    func = glXGetProcAddress((const GLubyte*)name);
-    if (!func) {
-        fprintf(stdout, "[GL]: failed to load extension: %s", name);
-        return NULL;
-    }
-    return func;
-}
-
-static int
-gl_error_handler(Display *dpy, XErrorEvent *ev)
-{
-    UNUSED((dpy, ev));
-    gl_err = TRUE;
-    return 0;
-}
-
-static int
-stricmpn(const char *a, const char *b, int len)
-{
-    int i = 0;
-    for (i = 0; i < len && a[i] && b[i]; ++i)
-        if (a[i] != b[i]) return 1;
-    if (i != len) return 1;
-    return 0;
-}
-
-static void
-device_init(struct device *dev)
-{
-    GLint status;
-    static const GLchar *vertex_shader =
-        "#version 300 es\n"
-        "uniform mat4 ProjMtx;\n"
-        "in vec2 Position;\n"
-        "in vec2 TexCoord;\n"
-        "in vec4 Color;\n"
-        "out vec2 Frag_UV;\n"
-        "out vec4 Frag_Color;\n"
-        "void main() {\n"
-        "   Frag_UV = TexCoord;\n"
-        "   Frag_Color = Color;\n"
-        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
-        "}\n";
-    static const GLchar *fragment_shader =
-        "#version 300 es\n"
-        "precision mediump float;\n"
-        "uniform sampler2D Texture;\n"
-        "in vec2 Frag_UV;\n"
-        "in vec4 Frag_Color;\n"
-        "out vec4 Out_Color;\n"
-        "void main(){\n"
-        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
-        "}\n";
-
-    dev->prog = glCreateProgram();
-    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
-    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
-    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
-    glCompileShader(dev->vert_shdr);
-    glCompileShader(dev->frag_shdr);
-    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glAttachShader(dev->prog, dev->vert_shdr);
-    glAttachShader(dev->prog, dev->frag_shdr);
-    glLinkProgram(dev->prog);
-    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
-    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
-    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
-    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
-    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
-
-    {
-        /* buffer setup */
-        GLsizei vs = sizeof(struct zr_draw_vertex);
-        size_t vp = offsetof(struct zr_draw_vertex, position);
-        size_t vt = offsetof(struct zr_draw_vertex, uv);
-        size_t vc = offsetof(struct zr_draw_vertex, col);
-
-        glGenBuffers(1, &dev->vbo);
-        glGenBuffers(1, &dev->ebo);
-        glGenVertexArrays(1, &dev->vao);
-
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
-        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
-        glEnableVertexAttribArray((GLuint)dev->attrib_col);
-
-        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
-        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
-        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
-    }
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-}
-
-static void
-device_upload_atlas(struct device *dev, const void *image, int width, int height)
-{
-    glGenTextures(1, &dev->font_tex);
-    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, image);
-}
-
-static void
-device_shutdown(struct device *dev)
-{
-    glDetachShader(dev->prog, dev->vert_shdr);
-    glDetachShader(dev->prog, dev->frag_shdr);
-    glDeleteShader(dev->vert_shdr);
-    glDeleteShader(dev->frag_shdr);
-    glDeleteProgram(dev->prog);
-    glDeleteTextures(1, &dev->font_tex);
-    glDeleteBuffers(1, &dev->vbo);
-    glDeleteBuffers(1, &dev->ebo);
-    glDeleteVertexArrays(1, &dev->vao);
-}
-
-static void
-device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
-    enum zr_anti_aliasing AA)
-{
-    GLint last_prog, last_tex;
-    GLint last_ebo, last_vbo, last_vao;
-    GLfloat ortho[4][4] = {
-        {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},
-    };
-    ortho[0][0] /= (GLfloat)width;
-    ortho[1][1] /= (GLfloat)height;
-
-    /* save previous opengl state */
-    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
-    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
-    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
-    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
-
-    /* setup global state */
-    glEnable(GL_BLEND);
-    glBlendEquation(GL_FUNC_ADD);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-    glEnable(GL_SCISSOR_TEST);
-    glActiveTexture(GL_TEXTURE0);
-
-    /* setup program */
-    glUseProgram(dev->prog);
-    glUniform1i(dev->uniform_tex, 0);
-    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
-
-    {
-        /* convert from command queue into draw list and draw to screen */
-        void *vertices, *elements;
-        const struct zr_draw_command *cmd;
-        const zr_draw_index *offset = NULL;
-
-        /* allocate vertex and element buffer */
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
-
-        /* load draw vertices & elements directly into vertex + element buffer */
-        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
-        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
-        {
-            struct zr_buffer vbuf, ebuf;
-
-            /* fill converting configuration */
-            struct zr_convert_config config;
-            memset(&config, 0, sizeof(config));
-            config.global_alpha = 1.0f;
-            config.shape_AA = AA;
-            config.line_AA = AA;
-            config.circle_segment_count = 22;
-            config.arc_segment_count = 22;
-            config.curve_segment_count = 22;
-            config.null = dev->null;
-
-            /* setup buffers to load vertices and elements */
-            zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
-            zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
-            zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
-        }
-        glUnmapBuffer(GL_ARRAY_BUFFER);
-        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-
-        /* iterate over and execute each draw command */
-        zr_draw_foreach(cmd, ctx, &dev->cmds) {
-            if (!cmd->elem_count) continue;
-            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-            glScissor((GLint)cmd->clip_rect.x,
-                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
-                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
-            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-            offset += cmd->elem_count;
-        }
-        zr_clear(ctx);
-    }
-
-    /* restore old state */
-    glUseProgram((GLuint)last_prog);
-    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
-    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
-    glBindVertexArray((GLuint)last_vao);
-    glDisable(GL_SCISSOR_TEST);
-}
-
-
-static void
-input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down)
-{
-    int ret;
-    KeySym *code = XGetKeyboardMapping(xw->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
-    if (*code == XK_Shift_L || *code == XK_Shift_R)
-        zr_input_key(ctx, ZR_KEY_SHIFT, down);
-    else if (*code == XK_Delete)
-        zr_input_key(ctx, ZR_KEY_DEL, down);
-    else if (*code == XK_Return)
-        zr_input_key(ctx, ZR_KEY_ENTER, down);
-    else if (*code == XK_Tab)
-        zr_input_key(ctx, ZR_KEY_TAB, down);
-    else if (*code == XK_space && !down)
-        zr_input_char(ctx, ' ');
-    else if (*code == XK_Left)
-        zr_input_key(ctx, ZR_KEY_LEFT, down);
-    else if (*code == XK_Right)
-        zr_input_key(ctx, ZR_KEY_RIGHT, down);
-    else if (*code == XK_BackSpace)
-        zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
-    else if (*code > 32 && *code < 128) {
-        if (*code == 'c')
-            zr_input_key(ctx, ZR_KEY_COPY, down && (evt->xkey.state & ControlMask));
-        else if (*code == 'v')
-            zr_input_key(ctx, ZR_KEY_PASTE, down && (evt->xkey.state & ControlMask));
-        else if (*code == 'x')
-            zr_input_key(ctx, ZR_KEY_CUT, down && (evt->xkey.state & ControlMask));
-        if (!down)
-            zr_input_unicode(ctx, (zr_rune)*code);
-    }
-    XFree(code);
-}
-
-static void
-input_motion(struct zr_context *ctx, XEvent *evt)
-{
-    const int x = evt->xmotion.x;
-    const int y = evt->xmotion.y;
-    zr_input_motion(ctx, x, y);
-}
-
-static void
-input_button(struct zr_context *ctx, XEvent *evt, int down)
-{
-    const int x = evt->xbutton.x;
-    const int y = evt->xbutton.y;
-    if (evt->xbutton.button == Button1)
-        zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
-    else if (evt->xbutton.button == Button2)
-        zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
-    else if (evt->xbutton.button == Button3)
-        zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
-    else if (evt->xbutton.button == Button4)
-        zr_input_scroll(ctx, 1.0f);
-    else if (evt->xbutton.button == Button5)
-        zr_input_scroll(ctx, -1.0f);
-}
-
-int main(int argc, char **argv)
-{
-    int i;
-    int running = 1;
-    const char *font_path;
-    struct opengl gl;
-    struct device device;
-    struct demo gui;
-    struct zr_font *font;
-    struct zr_font_atlas atlas;
-    struct XWindow win;
-
-    memset(&gl, 0, sizeof(gl));
-    memset(&win, 0, sizeof(win));
-    memset(&gui, 0, sizeof(gui));
-    font_path = (argc > 1) ? argv[1]: 0;
-
-    win.dpy = XOpenDisplay(NULL);
-    if (!win.dpy) die("Failed to open X display\n");
-    {
-        /* check glx version */
-        int glx_major, glx_minor;
-        if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))
-            die("[X11]: Error: Failed to query OpenGL version\n");
-        if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))
-            die("[X11]: Error: Invalid GLX version!\n");
-        fprintf(stdout, "[X11]: OpenGL version %d.%d\n", glx_major, glx_minor);
-    }
-    {
-        /* find and pick matching framebuffer visual */
-        int fb_count;
-        static GLint attr[] = {
-            GLX_X_RENDERABLE,   True,
-            GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,
-            GLX_RENDER_TYPE,    GLX_RGBA_BIT,
-            GLX_X_VISUAL_TYPE,  GLX_TRUE_COLOR,
-            GLX_RED_SIZE,       8,
-            GLX_GREEN_SIZE,     8,
-            GLX_BLUE_SIZE,      8,
-            GLX_ALPHA_SIZE,     8,
-            GLX_DEPTH_SIZE,     24,
-            GLX_STENCIL_SIZE,   8,
-            GLX_DOUBLEBUFFER,   True,
-            None
-        };
-        GLXFBConfig *fbc;
-        fprintf(stdout, "[X11]: Query matching framebuffer configurations\n");
-        fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
-        if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
-        fprintf(stdout, "[X11]: Found %d matching framebuffer configurations\n", fb_count);
-        {
-            /* pick framebuffer with most samples per pixel */
-            int fb_best = -1, best_num_samples = -1;
-            for (i = 0; i < fb_count; ++i) {
-                XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);
-                if (vi) {
-                    int sample_buffer, samples;
-                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);
-                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);
-                    fprintf(stdout, "\tFramebuffer Config %d: Visual ID 0x%2x: "
-                        "(SAMPLE_BUFFER: %d, SAMPLES: %d)\n", i, (unsigned int)vi->visualid,
-                        sample_buffer, samples);
-                    if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))
-                        fb_best = i; best_num_samples = samples;
-                }
-            }
-            win.fbc = fbc[fb_best];
-            XFree(fbc);
-            win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);
-            fprintf(stdout, "[X11]: Chosen visual id: 0x%x\n", (unsigned)win.vis->visualid);
-        }
-    }
-    {
-        /* create window */
-        fprintf(stdout, "[X11]: Creating colormap\n");
-        win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);
-        win.swa.colormap =  win.cmap;
-        win.swa.background_pixmap = None;
-        win.swa.border_pixel = 0;
-        win.swa.event_mask =
-            ExposureMask | KeyPressMask | KeyReleaseMask |
-            ButtonPress | ButtonReleaseMask| ButtonMotionMask |
-            Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
-            PointerMotionMask| StructureNotifyMask;
-        fprintf(stdout, "[X11]: Creating window\n");
-        win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,
-            WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,
-            win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);
-        if (!win.win) die("[X11]: Failed to create window\n");
-        XFree(win.vis);
-        XStoreName(win.dpy, win.win, "Zahnrad");
-        fprintf(stdout, "[X11]: Mapping window\n");
-        XMapWindow(win.dpy, win.win);
-    }
-    {
-        /* create opengl context */
-        int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
-        gl.extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
-        gl.create_context = (glxCreateContext)
-            glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
-
-        gl_err = FALSE;
-        if (!gl_check_extension(&gl, "GLX_ARB_create_context") || !gl.create_context) {
-            fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
-            fprintf(stdout, "[X11]: ... using old-style GLX context\n");
-            gl.ctx = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
-        } else {
-            GLint attr[] = {
-                GLX_CONTEXT_MAJOR_VERSION_ARB, OGL_MAJOR_VERSION,
-                GLX_CONTEXT_MINOR_VERSION_ARB, OGL_MINOR_VERSION,
-                None
-            };
-            fprintf(stdout, "[X11]: Creating Context...\n");
-            gl.ctx = gl.create_context(win.dpy, win.fbc, 0, True, attr);
-            XSync(win.dpy, False);
-            if (gl_err || !gl.ctx) {
-                /* Could not create GL 3.0 context. Fallback to old 2.x context.
-                 * If a version below 3.0 is requested, implementations will
-                 * return the newest context version compatible with OpenGL
-                 * version less than version 3.0.*/
-                attr[1] = 1; attr[3] = 0;
-                gl_err = FALSE;
-                fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
-                fprintf(stdout, "[X11] ... using old-style GLX context!\n");
-                gl.ctx = gl.create_context(win.dpy, win.fbc, 0, True, attr);
-            } else fprintf(stdout, "[X11] OpenGL 3.0 Context created\n");
-        }
-        XSync(win.dpy, False);
-        XSetErrorHandler(old_handler);
-        if (gl_err || !gl.ctx)
-            die("[X11]: Failed to create an OpenGL context\n");
-
-        if (!glXIsDirect(win.dpy, gl.ctx))
-            fprintf(stdout, "[X11] Optained indirect GLX rendering context\n");
-        else fprintf(stdout, "[X11] Optained direct GLX rendering context\n");
-        glXMakeCurrent(win.dpy, win.win, gl.ctx);
-    }
-    {
-        int failed = FALSE;
-        gl.version_str = (const char*)glGetString(GL_VERSION);
-        glGetIntegerv(GL_MAJOR_VERSION, &gl.major_version);
-        glGetIntegerv(GL_MINOR_VERSION, &gl.minor_version);
-        if (gl.major_version < 2)
-            die("[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n");
-        gl.version = (float)gl.major_version + (float)gl.minor_version * 0.1f;
-
-        gl.renderer_str = (const char*)glGetString(GL_RENDERER);
-        gl.extensions_str = (const char*)glGetString(GL_EXTENSIONS);
-        gl.glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
-
-        gl.vendor_str = (const char*)glGetString(GL_VENDOR);
-        if (!stricmpn(gl.vendor_str, "ATI", 4) ||
-            !stricmpn(gl.vendor_str, "AMD", 4))
-            gl.vendor = VENDOR_AMD;
-        else if (!stricmpn(gl.vendor_str, "NVIDIA", 6))
-            gl.vendor = VENDOR_NVIDIA;
-        else if (!stricmpn(gl.vendor_str, "Intel", 5))
-            gl.vendor = VENDOR_INTEL;
-        else gl.vendor = VENDOR_UNKNOWN;
-
-        fprintf(stdout, "[GL] OpenGL\n");
-        fprintf(stdout, "\tVersion: %d.%d\n", gl.major_version, gl.minor_version);
-        fprintf(stdout, "\tVendor: %s\n", gl.vendor_str);
-        fprintf(stdout, "\tRenderer: %s\n", gl.renderer_str);
-        fprintf(stdout, "\tGLSL: %s\n\n", gl.glsl_version_str);
-
-        /* Extensions */
-        fprintf(stdout, "[GL] Loading extensions...\n");
-        gl.glsl_available = (gl.version >= 2.0f);
-        if (gl.glsl_available) {
-            /* GLSL core in OpenGL > 2 */
-            glCreateShader = GL_EXT(glCreateShader);
-            glShaderSource = GL_EXT(glShaderSource);
-            glCompileShader = GL_EXT(glCompileShader);
-            glGetShaderiv = GL_EXT(glGetShaderiv);
-            glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog);
-            glDeleteShader = GL_EXT(glDeleteShader);
-            glCreateProgram = GL_EXT(glCreateProgram);
-            glAttachShader = GL_EXT(glAttachShader);
-            glDetachShader = GL_EXT(glDetachShader);
-            glLinkProgram = GL_EXT(glLinkProgram);
-            glUseProgram = GL_EXT(glUseProgram);
-            glGetProgramiv = GL_EXT(glGetProgramiv);
-            glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog);
-            glDeleteProgram = GL_EXT(glDeleteProgram);
-            glGetUniformLocation = GL_EXT(glGetUniformLocation);
-            glGetAttribLocation = GL_EXT(glGetAttribLocation);
-            glUniform1i = GL_EXT(glUniform1i);
-            glUniform1f = GL_EXT(glUniform1f);
-            glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv);
-            glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv);
-        }
-        gl.vertex_buffer_obj_available = gl_check_extension(&gl, "GL_ARB_vertex_buffer_object");
-        if (gl.vertex_buffer_obj_available) {
-            /* GL_ARB_vertex_buffer_object */
-            glGenBuffers = GL_EXT(glGenBuffers);
-            glBindBuffer = GL_EXT(glBindBuffer);
-            glBufferData = GL_EXT(glBufferData);
-            glBufferSubData = GL_EXT(glBufferSubData);
-            glMapBuffer = GL_EXT(glMapBuffer);
-            glUnmapBuffer = GL_EXT(glUnmapBuffer);
-            glDeleteBuffers = GL_EXT(glDeleteBuffers);
-        }
-        gl.fragment_program_available = gl_check_extension(&gl, "GL_ARB_fragment_program");
-        if (gl.fragment_program_available) {
-            /* GL_ARB_vertex_program / GL_ARB_fragment_program  */
-            glVertexAttribPointer = GL_EXT(glVertexAttribPointer);
-            glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray);
-            glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray);
-        }
-        gl.vertex_array_obj_available = gl_check_extension(&gl, "GL_ARB_vertex_array_object");
-        if (gl.vertex_array_obj_available) {
-            /* GL_ARB_vertex_array_object */
-            glGenVertexArrays = GL_EXT(glGenVertexArrays);
-            glBindVertexArray = GL_EXT(glBindVertexArray);
-            glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays);
-        }
-        gl.frame_buffer_object_available = gl_check_extension(&gl, "GL_ARB_framebuffer_object");
-        if (gl.frame_buffer_object_available) {
-            /* GL_ARB_framebuffer_object */
-            glGenerateMipmap = GL_EXT(glGenerateMipmap);
-        }
-        if (!gl.vertex_buffer_obj_available) {
-            fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n");
-            failed = TRUE;
-        }
-        if (!gl.fragment_program_available) {
-            fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n");
-            failed = TRUE;
-        }
-        if (!gl.vertex_array_obj_available) {
-            fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n");
-            failed = TRUE;
-        }
-        if (!gl.frame_buffer_object_available) {
-            fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n");
-            failed = TRUE;
-        }
-        if (failed) goto cleanup;
-        fprintf(stdout, "[GL] Extensions successfully loaded\n");
-    }
-
-    /* screen */
-    XGetWindowAttributes(win.dpy, win.win, &win.attr);
-    win.width = win.attr.width;
-    win.height = win.attr.height;
-
-    device_init(&device);
-    {
-        /* Font */
-        const void *image;
-        int width, height;
-
-        zr_font_atlas_init_default(&atlas);
-        zr_font_atlas_begin(&atlas);
-        if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
-        else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
-        image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
-        device_upload_atlas(&device, image, width, height);
-        zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
-
-        /* GUI */
-        memset(&gui, 0, sizeof(gui));
-        zr_buffer_init_default(&device.cmds);
-        zr_init_default(&gui.ctx, &font->handle);
-    }
-
-
-    device_init(&device);
-    glEnable(GL_TEXTURE_2D);
-    gui.icons.unchecked = icon_load("../../icon/unchecked.png");
-    gui.icons.checked = icon_load("../../icon/checked.png");
-    gui.icons.rocket = icon_load("../../icon/rocket.png");
-    gui.icons.cloud = icon_load("../../icon/cloud.png");
-    gui.icons.pen = icon_load("../../icon/pen.png");
-    gui.icons.play = icon_load("../../icon/play.png");
-    gui.icons.pause = icon_load("../../icon/pause.png");
-    gui.icons.stop = icon_load("../../icon/stop.png");
-    gui.icons.next =  icon_load("../../icon/next.png");
-    gui.icons.prev =  icon_load("../../icon/prev.png");
-    gui.icons.tools = icon_load("../../icon/tools.png");
-    gui.icons.dir = icon_load("../../icon/directory.png");
-    gui.icons.copy = icon_load("../../icon/copy.png");
-    gui.icons.convert = icon_load("../../icon/export.png");
-    gui.icons.del = icon_load("../../icon/delete.png");
-    gui.icons.edit = icon_load("../../icon/edit.png");
-    gui.icons.menu[0] = icon_load("../../icon/home.png");
-    gui.icons.menu[1] = icon_load("../../icon/phone.png");
-    gui.icons.menu[2] = icon_load("../../icon/plane.png");
-    gui.icons.menu[3] = icon_load("../../icon/wifi.png");
-    gui.icons.menu[4] = icon_load("../../icon/settings.png");
-    gui.icons.menu[5] = icon_load("../../icon/volume.png");
-
-    gui.icons.home = icon_load("../../icon/home.png");
-    gui.icons.directory = icon_load("../../icon/directory.png");
-    gui.icons.computer = icon_load("../../icon/computer.png");
-    gui.icons.desktop = icon_load("../../icon/desktop.png");
-    gui.icons.default_file = icon_load("../../icon/default.png");
-    gui.icons.text_file = icon_load("../../icon/text.png");
-    gui.icons.music_file = icon_load("../../icon/music.png");
-    gui.icons.font_file =  icon_load("../../icon/font.png");
-    gui.icons.img_file = icon_load("../../icon/img.png");
-    gui.icons.movie_file = icon_load("../../icon/movie.png");
-
-    for (i = 0; i < 9; ++i) {
-        char buffer[256];
-        sprintf(buffer, "../../images/image%d.png", (i+1));
-        gui.icons.images[i] = icon_load(buffer);
-    }
-
-    while (running) {
-        /* input */
-        XEvent evt;
-        zr_input_begin(&gui.ctx);
-        while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)) {
-            if (evt.type == KeyPress)
-                input_key(&win, &gui.ctx, &evt, zr_true);
-            else if (evt.type == KeyRelease)
-                input_key(&win, &gui.ctx, &evt, zr_false);
-            else if (evt.type == ButtonPress)
-                input_button(&gui.ctx, &evt, zr_true);
-            else if (evt.type == ButtonRelease)
-                input_button(&gui.ctx, &evt, zr_false);
-            else if (evt.type == MotionNotify)
-                input_motion(&gui.ctx, &evt);
-            else if (evt.type == Expose || evt.type == ConfigureNotify) {
-                XGetWindowAttributes(win.dpy, win.win, &win.attr);
-                win.width = win.attr.width;
-                win.height = win.attr.height;
-            }
-        }
-        zr_input_end(&gui.ctx);
-
-        /* GUI */
-        XGetWindowAttributes(win.dpy, win.win, &win.attr);
-        running = run_demo(&gui);
-
-        /* Draw */
-        glClear(GL_COLOR_BUFFER_BIT);
-        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
-        glViewport(0, 0, win.width, win.height);
-        device_draw(&device, &gui.ctx, win.width, win.height, ZR_ANTI_ALIASING_ON);
-        glXSwapBuffers(win.dpy, win.win);
-    }
-
-cleanup:
-    zr_font_atlas_clear(&atlas);
-    zr_free(&gui.ctx);
-    zr_buffer_free(&device.cmds);
-    device_shutdown(&device);
-
-    glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
-
-    glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
-
-    for (i = 0; i < 9; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
-    for (i = 0; i < 6; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
-
-    glXMakeCurrent(win.dpy, 0, 0);
-    glXDestroyContext(win.dpy, gl.ctx);
-    XUnmapWindow(win.dpy, win.win);
-    XFreeColormap(win.dpy, win.cmap);
-    XDestroyWindow(win.dpy, win.win);
-    XCloseDisplay(win.dpy);
-    return 0;
-}
-

+ 1 - 1
demo/sdl/Makefile

@@ -8,7 +8,7 @@ DCC = gcc
 # Flags
 CFLAGS = -std=c99 -pedantic -O2
 
-SRC = ../../zahnrad.c sdl.c
+SRC = main.c
 OBJ = $(SRC:.c=.o)
 
 ifeq ($(OS),Windows_NT)

+ 142 - 0
demo/sdl/main.c

@@ -0,0 +1,142 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <SDL2/SDL.h>
+
+/* these defines are both needed for the header
+ * and source file. So if you split them remember
+ * to copy them as well. */
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#include "nuklear_sdl.h"
+#include "nuklear_sdl.c"
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+int
+main(void)
+{
+    /* Platform */
+    SDL_Window *win;
+    SDL_GLContext glContext;
+    struct nk_color background;
+    int win_width, win_height;
+    int running = 1;
+
+    /* GUI */
+    struct nk_context *ctx;
+
+    /* SDL setup */
+    SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+    win = SDL_CreateWindow("Demo",
+        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
+    glContext = SDL_GL_CreateContext(win);
+    SDL_GetWindowSize(win, &win_width, &win_height);
+
+    /* OpenGL setup */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    ctx = nk_sdl_init(win);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    {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 *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-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();
+    /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+    background = nk_rgb(28,48,62);
+    while (running)
+    {
+        /* Input */
+        SDL_Event evt;
+        nk_input_begin(ctx);
+        while (SDL_PollEvent(&evt)) {
+            if (evt.type == SDL_QUIT) goto cleanup;
+            nk_sdl_handle_event(&evt);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        {struct nk_panel layout;
+        if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 210, 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", NK_BUTTON_DEFAULT))
+                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, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            {struct nk_panel combo;
+            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, &combo, background, 400)) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }}
+        }
+        nk_end(ctx);}
+
+        /* Draw */
+        {float bg[4];
+        nk_color_fv(bg, background);
+        SDL_GetWindowSize(win, &win_width, &win_height);
+        glViewport(0, 0, win_width, win_height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(bg[0], bg[1], bg[2], bg[3]);
+        nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
+        SDL_GL_SwapWindow(win);}
+    }
+
+cleanup:
+    nk_sdl_shutdown();
+    SDL_GL_DeleteContext(glContext);
+    SDL_DestroyWindow(win);
+    SDL_Quit();
+    return 0;
+}
+

+ 369 - 0
demo/sdl/nuklear_sdl.c

@@ -0,0 +1,369 @@
+#include <string.h>
+#include <SDL2/SDL.h>
+
+#include "nuklear_sdl.h"
+#define NK_IMPLEMENTATION
+#include "../../nuklear.h"
+
+struct nk_sdl_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+static struct nk_sdl {
+    SDL_Window *win;
+    struct nk_sdl_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+} sdl;
+
+NK_API void
+nk_sdl_device_create(void)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    struct nk_sdl_device *dev = &sdl.ogl;
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sdl_device_destroy(void)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+    struct nk_sdl_device *dev = &sdl.ogl;
+    int width, height;
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    SDL_GetWindowSize(sdl.win, &width, &height);
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
+            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(&sdl.ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+static void
+nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    const char *text = SDL_GetClipboardText();
+    if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+    (void)usr;
+}
+
+static void
+nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+    char *str = 0;
+    (void)usr;
+    if (!len) return;
+    str = malloc((size_t)len+1);
+    if (!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+    SDL_SetClipboardText(str);
+    free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+    sdl.win = win;
+    nk_init_default(&sdl.ctx, 0);
+    sdl.ctx.clip.copy = nk_sdl_clipbard_copy;
+    sdl.ctx.clip.paste = nk_sdl_clipbard_paste;
+    sdl.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_sdl_device_create();
+    return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&sdl.atlas);
+    nk_font_atlas_begin(&sdl.atlas);
+    *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+    const void *image; int w, h;
+    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sdl_device_upload_atlas(image, w, h);
+    nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null);
+    if (sdl.atlas.default_font)
+        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+
+}
+
+NK_API void
+nk_sdl_handle_event(SDL_Event *evt)
+{
+    struct nk_context *ctx = &sdl.ctx;
+    if (evt->type == SDL_WINDOWEVENT) {
+        /* handle window resizing */
+        if (evt->window.event != SDL_WINDOWEVENT_RESIZED) return;
+        glViewport(0, 0, evt->window.data1, evt->window.data2);
+    } else if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) {
+        /* key events */
+        int down = evt->type == SDL_KEYDOWN;
+        const Uint8* state = SDL_GetKeyboardState(0);
+        SDL_Keycode sym = evt->key.keysym.sym;
+        if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
+            nk_input_key(ctx, NK_KEY_SHIFT, down);
+        else if (sym == SDLK_DELETE)
+            nk_input_key(ctx, NK_KEY_DEL, down);
+        else if (sym == SDLK_RETURN)
+            nk_input_key(ctx, NK_KEY_ENTER, down);
+        else if (sym == SDLK_TAB)
+            nk_input_key(ctx, NK_KEY_TAB, down);
+        else if (sym == SDLK_BACKSPACE)
+            nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+        else if (sym == SDLK_HOME)
+            nk_input_key(ctx, NK_KEY_TEXT_START, down);
+        else if (sym == SDLK_END)
+            nk_input_key(ctx, NK_KEY_TEXT_END, down);
+        else if (sym == SDLK_z)
+            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_r)
+            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_c)
+            nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_v)
+            nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_x)
+            nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_b)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == SDLK_e)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]);
+        else if (sym == 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);
+        } else if (sym == 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);
+        }
+    } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
+        /* mouse button */
+        int down = evt->type == SDL_MOUSEBUTTONDOWN;
+        const int x = evt->button.x, y = evt->button.y;
+        if (evt->button.button == SDL_BUTTON_LEFT)
+            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        if (evt->button.button == SDL_BUTTON_MIDDLE)
+            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+        if (evt->button.button == SDL_BUTTON_RIGHT)
+            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+    } else if (evt->type == SDL_MOUSEMOTION) {
+        nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+    } else if (evt->type == SDL_TEXTINPUT) {
+        nk_glyph glyph;
+        memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+        nk_input_glyph(ctx, glyph);
+    } else if (evt->type == SDL_MOUSEWHEEL) {
+        nk_input_scroll(ctx,(float)evt->wheel.y);
+    }
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+    nk_font_atlas_clear(&sdl.atlas);
+    nk_free(&sdl.ctx);
+    nk_sdl_device_destroy();
+}
+

+ 18 - 0
demo/sdl/nuklear_sdl.h

@@ -0,0 +1,18 @@
+#ifndef NK_SDL_H_
+#define NK_SDL_H_
+
+#include "../../nuklear.h"
+
+#include <SDL2/SDL.h>
+
+NK_API struct nk_context *nk_sdl_init(SDL_Window *win);
+NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_sdl_font_stash_end(void);
+NK_API void nk_sdl_handle_event(SDL_Event *evt);
+NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_sdl_shutdown(void);
+
+NK_API void nk_sdl_device_destroy(void);
+NK_API void nk_sdl_device_create(void);
+
+#endif

+ 0 - 568
demo/sdl/sdl.c

@@ -1,568 +0,0 @@
-/*
-    Copyright (c) 2016 Micha Mettke
-
-    This software is provided 'as-is', without any express or implied
-    warranty.  In no event will the authors be held liable for any damages
-    arising from the use of this software.
-
-    Permission is granted to anyone to use this software for any purpose,
-    including commercial applications, and to alter it and redistribute it
-    freely, subject to the following restrictions:
-
-    1.  The origin of this software must not be misrepresented; you must not
-        claim that you wrote the original software. If you use this software
-        in a product, an acknowledgment in the product documentation would be
-        appreciated but is not required.
-    2.  Altered source versions must be plainly marked as such, and must not be
-        misrepresented as being the original software.
-    3.  This notice may not be removed or altered from any source distribution.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include <math.h>
-
-#include <GL/glew.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#include <SDL2/SDL.h>
-
-/* macros */
-#define MAX_VERTEX_MEMORY 512 * 1024
-#define MAX_ELEMENT_MEMORY 128 * 1024
-
-#include "../../zahnrad.h"
-#include "../demo.c"
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#pragma clang diagnostic ignored "-Wbad-function-cast"
-#pragma clang diagnostic ignored "-Wcast-qual"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
-#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
-#pragma clang diagnostic ignored "-Wunused-function"
-#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#pragma GCC diagnostic ignored "-Wconversion"
-#pragma GCC diagnostic ignored "-Wbad-function-cast"
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
-#pragma GCC diagnostic ignored "-Wtype-limits"
-#pragma GCC diagnostic ignored "-Wswitch-default"
-#pragma GCC diagnostic ignored "-Wunused-function"
-#elif _MSC_VER
-#pragma warning (push)
-#pragma warning (disable: 4456)
-#endif
-
-#define STB_IMAGE_IMPLEMENTATION
-#include "../stb_image.h"
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#elif defined(__GNUC__) || defined(__GNUG__)
-#pragma GCC diagnostic pop
-#elif _MSC_VER
-#pragma warning (pop)
-#endif
-
-
-/* ==============================================================
- *
- *                      Utility
- *
- * ===============================================================*/
-static void
-die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fputs("\n", stderr);
-    exit(EXIT_FAILURE);
-}
-
-static struct zr_image
-icon_load(const char *filename)
-{
-    int x,y,n;
-    GLuint tex;
-    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
-    if (!data) die("[SDL]: failed to load image: %s", filename);
-
-    glGenTextures(1, &tex);
-    glBindTexture(GL_TEXTURE_2D, tex);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-    glGenerateMipmap(GL_TEXTURE_2D);
-    stbi_image_free(data);
-    return zr_image_id((int)tex);
-}
-
-struct device {
-    GLuint vbo, vao, ebo;
-    GLuint prog;
-    GLuint vert_shdr;
-    GLuint frag_shdr;
-    GLint attrib_pos;
-    GLint attrib_uv;
-    GLint attrib_col;
-    GLint uniform_tex;
-    GLint uniform_proj;
-    GLuint font_tex;
-    struct zr_draw_null_texture null;
-    struct zr_buffer cmds;
-};
-
-static void
-device_init(struct device *dev)
-{
-    GLint status;
-    static const GLchar *vertex_shader =
-        "#version 300 es\n"
-        "uniform mat4 ProjMtx;\n"
-        "in vec2 Position;\n"
-        "in vec2 TexCoord;\n"
-        "in vec4 Color;\n"
-        "out vec2 Frag_UV;\n"
-        "out vec4 Frag_Color;\n"
-        "void main() {\n"
-        "   Frag_UV = TexCoord;\n"
-        "   Frag_Color = Color;\n"
-        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
-        "}\n";
-    static const GLchar *fragment_shader =
-        "#version 300 es\n"
-        "precision mediump float;\n"
-        "uniform sampler2D Texture;\n"
-        "in vec2 Frag_UV;\n"
-        "in vec4 Frag_Color;\n"
-        "out vec4 Out_Color;\n"
-        "void main(){\n"
-        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
-        "}\n";
-
-    dev->prog = glCreateProgram();
-    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
-    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
-    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
-    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
-    glCompileShader(dev->vert_shdr);
-    glCompileShader(dev->frag_shdr);
-    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
-    assert(status == GL_TRUE);
-    glAttachShader(dev->prog, dev->vert_shdr);
-    glAttachShader(dev->prog, dev->frag_shdr);
-    glLinkProgram(dev->prog);
-    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
-    assert(status == GL_TRUE);
-
-    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
-    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
-    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
-    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
-    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
-
-    {
-        /* buffer setup */
-        GLsizei vs = sizeof(struct zr_draw_vertex);
-        size_t vp = offsetof(struct zr_draw_vertex, position);
-        size_t vt = offsetof(struct zr_draw_vertex, uv);
-        size_t vc = offsetof(struct zr_draw_vertex, col);
-
-        glGenBuffers(1, &dev->vbo);
-        glGenBuffers(1, &dev->ebo);
-        glGenVertexArrays(1, &dev->vao);
-
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
-        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
-        glEnableVertexAttribArray((GLuint)dev->attrib_col);
-
-        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
-        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
-        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
-    }
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glBindVertexArray(0);
-}
-
-static void
-device_upload_atlas(struct device *dev, const void *image, int width, int height)
-{
-    glGenTextures(1, &dev->font_tex);
-    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, image);
-}
-
-static void
-device_shutdown(struct device *dev)
-{
-    glDetachShader(dev->prog, dev->vert_shdr);
-    glDetachShader(dev->prog, dev->frag_shdr);
-    glDeleteShader(dev->vert_shdr);
-    glDeleteShader(dev->frag_shdr);
-    glDeleteProgram(dev->prog);
-    glDeleteTextures(1, &dev->font_tex);
-    glDeleteBuffers(1, &dev->vbo);
-    glDeleteBuffers(1, &dev->ebo);
-    glDeleteVertexArrays(1, &dev->vao);
-}
-
-static void
-device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
-    enum zr_anti_aliasing AA)
-{
-    GLint last_prog, last_tex;
-    GLint last_ebo, last_vbo, last_vao;
-    GLfloat ortho[4][4] = {
-        {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},
-    };
-    ortho[0][0] /= (GLfloat)width;
-    ortho[1][1] /= (GLfloat)height;
-
-    /* save previous opengl state */
-    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
-    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
-    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
-    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
-    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
-
-    /* setup global state */
-    glEnable(GL_BLEND);
-    glBlendEquation(GL_FUNC_ADD);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_CULL_FACE);
-    glDisable(GL_DEPTH_TEST);
-    glEnable(GL_SCISSOR_TEST);
-    glActiveTexture(GL_TEXTURE0);
-
-    /* setup program */
-    glUseProgram(dev->prog);
-    glUniform1i(dev->uniform_tex, 0);
-    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
-    {
-        /* convert from command queue into draw list and draw to screen */
-        const struct zr_draw_command *cmd;
-        void *vertices, *elements;
-        const zr_draw_index *offset = NULL;
-
-        /* allocate vertex and element buffer */
-        glBindVertexArray(dev->vao);
-        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
-
-        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
-
-        /* load draw vertices & elements directly into vertex + element buffer */
-        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
-        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
-        {
-            struct zr_buffer vbuf, ebuf;
-
-            /* fill converting configuration */
-            struct zr_convert_config config;
-            memset(&config, 0, sizeof(config));
-            config.circle_segment_count = 22;
-            config.arc_segment_count = 22;
-            config.curve_segment_count = 22;
-            config.global_alpha = 1.0f;
-            config.null = dev->null;
-            config.shape_AA = AA;
-            config.line_AA = AA;
-
-            /* setup buffers to load vertices and elements */
-            zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
-            zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
-            zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
-        }
-        glUnmapBuffer(GL_ARRAY_BUFFER);
-        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
-
-        /* iterate over and execute each draw command */
-        zr_draw_foreach(cmd, ctx, &dev->cmds)
-        {
-            if (!cmd->elem_count) continue;
-            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
-            glScissor((GLint)cmd->clip_rect.x,
-                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
-                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
-            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
-            offset += cmd->elem_count;
-        }
-        zr_clear(ctx);
-    }
-    /* restore old state */
-    glUseProgram((GLuint)last_prog);
-    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
-    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
-    glBindVertexArray((GLuint)last_vao);
-    glDisable(GL_SCISSOR_TEST);
-    glDisable(GL_BLEND);
-}
-
-static void
-input_key(struct zr_context *ctx, SDL_Event *evt, int down)
-{
-    const Uint8* state = SDL_GetKeyboardState(NULL);
-    SDL_Keycode sym = evt->key.keysym.sym;
-    if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
-        zr_input_key(ctx, ZR_KEY_SHIFT, down);
-    else if (sym == SDLK_DELETE)
-        zr_input_key(ctx, ZR_KEY_DEL, down);
-    else if (sym == SDLK_RETURN)
-        zr_input_key(ctx, ZR_KEY_ENTER, down);
-    else if (sym == SDLK_TAB)
-        zr_input_key(ctx, ZR_KEY_TAB, down);
-    else if (sym == SDLK_BACKSPACE)
-        zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
-    else if (sym == SDLK_LEFT)
-        zr_input_key(ctx, ZR_KEY_LEFT, down);
-    else if (sym == SDLK_RIGHT)
-        zr_input_key(ctx, ZR_KEY_RIGHT, down);
-    else if (sym == SDLK_c)
-        zr_input_key(ctx, ZR_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
-    else if (sym == SDLK_v)
-        zr_input_key(ctx, ZR_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
-    else if (sym == SDLK_x)
-        zr_input_key(ctx, ZR_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
-}
-
-static void
-input_motion(struct zr_context *ctx, SDL_Event *evt)
-{
-    const int x = evt->motion.x;
-    const int y = evt->motion.y;
-    zr_input_motion(ctx, x, y);
-}
-
-static void
-input_button(struct zr_context *ctx, SDL_Event *evt, int down)
-{
-    const int x = evt->button.x;
-    const int y = evt->button.y;
-    if (evt->button.button == SDL_BUTTON_LEFT)
-        zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
-    if (evt->button.button == SDL_BUTTON_MIDDLE)
-        zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
-    if (evt->button.button == SDL_BUTTON_RIGHT)
-        zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
-}
-
-static void
-input_text(struct zr_context *ctx, SDL_Event *evt)
-{
-    zr_glyph glyph;
-    memcpy(glyph, evt->text.text, ZR_UTF_SIZE);
-    zr_input_glyph(ctx, glyph);
-}
-
-static void
-resize(SDL_Event *evt)
-{
-    if (evt->window.event != SDL_WINDOWEVENT_RESIZED) return;
-    glViewport(0, 0, evt->window.data1, evt->window.data2);
-}
-
-int
-main(int argc, char *argv[])
-{
-    /* Platform */
-    int i;
-    const char *font_path;
-    SDL_Window *win;
-    SDL_GLContext glContext;
-    int win_width, win_height;
-    int running = 1;
-
-    /* GUI */
-    struct device device;
-    struct demo gui;
-    struct zr_font *font;
-    struct zr_font_atlas atlas;
-    font_path = (argc > 1) ? argv[1]: 0;
-
-    /* SDL */
-    SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-    win = SDL_CreateWindow("Demo",
-        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
-    glContext = SDL_GL_CreateContext(win);
-    SDL_GetWindowSize(win, &win_width, &win_height);
-
-    /* OpenGL */
-    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
-    glewExperimental = 1;
-    if (glewInit() != GLEW_OK)
-        die("Failed to setup GLEW\n");
-
-    device_init(&device);
-    {
-        /* Font */
-        const void *image;
-        int width, height;
-
-        zr_font_atlas_init_default(&atlas);
-        zr_font_atlas_begin(&atlas);
-        if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
-        else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
-        image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
-        device_upload_atlas(&device, image, width, height);
-        zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
-
-        /* GUI */
-        memset(&gui, 0, sizeof(gui));
-        zr_buffer_init_default(&device.cmds);
-        zr_init_default(&gui.ctx, &font->handle);
-    }
-
-    /* icons */
-    glEnable(GL_TEXTURE_2D);
-    gui.icons.unchecked = icon_load("../../icon/unchecked.png");
-    gui.icons.checked = icon_load("../../icon/checked.png");
-    gui.icons.rocket = icon_load("../../icon/rocket.png");
-    gui.icons.cloud = icon_load("../../icon/cloud.png");
-    gui.icons.pen = icon_load("../../icon/pen.png");
-    gui.icons.play = icon_load("../../icon/play.png");
-    gui.icons.pause = icon_load("../../icon/pause.png");
-    gui.icons.stop = icon_load("../../icon/stop.png");
-    gui.icons.next =  icon_load("../../icon/next.png");
-    gui.icons.prev =  icon_load("../../icon/prev.png");
-    gui.icons.tools = icon_load("../../icon/tools.png");
-    gui.icons.dir = icon_load("../../icon/directory.png");
-    gui.icons.copy = icon_load("../../icon/copy.png");
-    gui.icons.convert = icon_load("../../icon/export.png");
-    gui.icons.del = icon_load("../../icon/delete.png");
-    gui.icons.edit = icon_load("../../icon/edit.png");
-    gui.icons.menu[0] = icon_load("../../icon/home.png");
-    gui.icons.menu[1] = icon_load("../../icon/phone.png");
-    gui.icons.menu[2] = icon_load("../../icon/plane.png");
-    gui.icons.menu[3] = icon_load("../../icon/wifi.png");
-    gui.icons.menu[4] = icon_load("../../icon/settings.png");
-    gui.icons.menu[5] = icon_load("../../icon/volume.png");
-
-    gui.icons.home = icon_load("../../icon/home.png");
-    gui.icons.directory = icon_load("../../icon/directory.png");
-    gui.icons.computer = icon_load("../../icon/computer.png");
-    gui.icons.desktop = icon_load("../../icon/desktop.png");
-    gui.icons.default_file = icon_load("../../icon/default.png");
-    gui.icons.text_file = icon_load("../../icon/text.png");
-    gui.icons.music_file = icon_load("../../icon/music.png");
-    gui.icons.font_file =  icon_load("../../icon/font.png");
-    gui.icons.img_file = icon_load("../../icon/img.png");
-    gui.icons.movie_file = icon_load("../../icon/movie.png");
-
-    for (i = 0; i < 9; ++i) {
-        char buffer[256];
-        sprintf(buffer, "../../images/image%d.png", (i+1));
-        gui.icons.images[i] = icon_load(buffer);
-    }
-
-    while (running) {
-        /* Input */
-        SDL_Event evt;
-        zr_input_begin(&gui.ctx);
-        while (SDL_PollEvent(&evt)) {
-            if (evt.type == SDL_WINDOWEVENT) resize(&evt);
-            else if (evt.type == SDL_QUIT) goto cleanup;
-            else if (evt.type == SDL_KEYUP)
-                input_key(&gui.ctx, &evt, zr_false);
-            else if (evt.type == SDL_KEYDOWN)
-                input_key(&gui.ctx, &evt, zr_true);
-            else if (evt.type == SDL_MOUSEBUTTONDOWN)
-                input_button(&gui.ctx, &evt, zr_true);
-            else if (evt.type == SDL_MOUSEBUTTONUP)
-                input_button(&gui.ctx, &evt, zr_false);
-            else if (evt.type == SDL_MOUSEMOTION)
-                input_motion(&gui.ctx, &evt);
-            else if (evt.type == SDL_TEXTINPUT)
-                input_text(&gui.ctx, &evt);
-            else if (evt.type == SDL_MOUSEWHEEL)
-                zr_input_scroll(&gui.ctx,(float)evt.wheel.y);
-        }
-        zr_input_end(&gui.ctx);
-
-        /* GUI */
-        SDL_GetWindowSize(win, &win_width, &win_height);
-        running = run_demo(&gui);
-
-        /* Draw */
-        glClear(GL_COLOR_BUFFER_BIT);
-        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
-        device_draw(&device, &gui.ctx, win_width, win_height, ZR_ANTI_ALIASING_ON);
-        SDL_GL_SwapWindow(win);
-    }
-
-cleanup:
-    /* Cleanup */
-    glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
-
-    glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
-    glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
-
-    for (i = 0; i < 9; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
-    for (i = 0; i < 6; ++i)
-        glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
-
-    zr_free(&gui.ctx);
-    zr_font_atlas_clear(&atlas);
-    zr_buffer_free(&device.cmds);
-    device_shutdown(&device);
-    SDL_GL_DeleteContext(glContext);
-    SDL_DestroyWindow(win);
-    SDL_Quit();
-    return 0;
-}
-

+ 1 - 1
demo/x11/Makefile

@@ -8,7 +8,7 @@ DCC = gcc
 # Flags
 CFLAGS = -std=c89 -pedantic -O2
 
-SRC = xlib.c ../../zahnrad.c
+SRC = main.c
 OBJ = $(SRC:.c=.o)
 
 # Modes

+ 167 - 0
demo/x11/main.c

@@ -0,0 +1,167 @@
+/* nuklear - v1.00 - public domain */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+
+#define DTIME       20
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#include "nuklear_xlib.h"
+#include "nuklear_xlib.c"
+
+typedef struct XWindow XWindow;
+struct XWindow {
+    Display *dpy;
+    Window root;
+    Visual *vis;
+    Colormap cmap;
+    XWindowAttributes attr;
+    XSetWindowAttributes swa;
+    Window win;
+    int screen;
+    XFont *font;
+    unsigned int width;
+    unsigned int height;
+};
+
+static void
+die(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fputs("\n", stderr);
+    exit(EXIT_FAILURE);
+}
+
+static void*
+xcalloc(size_t siz, size_t n)
+{
+    void *ptr = calloc(siz, n);
+    if (!ptr) die("Out of memory\n");
+    return ptr;
+}
+
+static long
+timestamp(void)
+{
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) < 0) return 0;
+    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
+static void
+sleep_for(long t)
+{
+    struct timespec req;
+    const time_t sec = (int)(t/1000);
+    const long ms = t - (sec * 1000);
+    req.tv_sec = sec;
+    req.tv_nsec = ms * 1000000L;
+    while(-1 == nanosleep(&req, &req));
+}
+
+int
+main(void)
+{
+    long dt;
+    long started;
+    int running = 1;
+    XWindow xw;
+    struct nk_context *ctx;
+
+    /* X11 */
+    memset(&xw, 0, sizeof xw);
+    xw.dpy = XOpenDisplay(NULL);
+    xw.root = DefaultRootWindow(xw.dpy);
+    xw.screen = XDefaultScreen(xw.dpy);
+    xw.vis = XDefaultVisual(xw.dpy, xw.screen);
+    xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
+    xw.swa.colormap = xw.cmap;
+    xw.swa.event_mask =
+        ExposureMask | KeyPressMask | KeyReleaseMask |
+        ButtonPress | ButtonReleaseMask| ButtonMotionMask |
+        Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
+        PointerMotionMask | KeymapStateMask;
+    xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
+        XDefaultDepth(xw.dpy, xw.screen), InputOutput,
+        xw.vis, CWEventMask | CWColormap, &xw.swa);
+    XStoreName(xw.dpy, xw.win, "X11");
+    XMapWindow(xw.dpy, xw.win);
+    XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
+    xw.width = (unsigned int)xw.attr.width;
+    xw.height = (unsigned int)xw.attr.height;
+
+
+    /* GUI */
+    xw.font = nk_xfont_create(xw.dpy, "fixed");
+    ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height);
+    while (running)
+    {
+        /* Input */
+        XEvent evt;
+        started = timestamp();
+        nk_input_begin(ctx);
+        while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)){
+            if (XFilterEvent(&evt, xw.win)) continue;
+            nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        {struct nk_panel layout;
+        if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 200, 300),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_CLOSABLE|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", NK_BUTTON_DEFAULT))
+                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, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+            nk_layout_row_dynamic(ctx, 100, 1);
+        }
+        nk_end(ctx);}
+        if (nk_window_is_closed(ctx, "Demo")) break;
+
+        /* Draw */
+        XClearWindow(xw.dpy, xw.win);
+        nk_xlib_render(xw.win, nk_rgb(30,30,30));
+        XFlush(xw.dpy);
+
+        /* Timing */
+        dt = timestamp() - started;
+        if (dt < DTIME)
+            sleep_for(DTIME - dt);
+    }
+
+    nk_xfont_del(xw.dpy, xw.font);
+    nk_xlib_shutdown();
+    XUnmapWindow(xw.dpy, xw.win);
+    XFreeColormap(xw.dpy, xw.cmap);
+    XDestroyWindow(xw.dpy, xw.win);
+    XCloseDisplay(xw.dpy);
+    return 0;
+}
+

+ 611 - 0
demo/x11/nuklear_xlib.c

@@ -0,0 +1,611 @@
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#define NK_IMPLEMENTATION
+#include "nuklear_xlib.h"
+#include "../../nuklear.h"
+
+typedef struct XSurface XSurface;
+struct XFont {
+    int ascent;
+    int descent;
+    int height;
+    XFontSet set;
+    XFontStruct *xfont;
+};
+struct XSurface {
+    GC gc;
+    Display *dpy;
+    int screen;
+    Window root;
+    Drawable drawable;
+    unsigned int w, h;
+};
+static struct  {
+    struct nk_context ctx;
+    struct XSurface *surf;
+} xlib;
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+static unsigned long
+color_from_byte(const nk_byte *c)
+{
+    unsigned long res = 0;
+    res |= (unsigned long)c[0] << 16;
+    res |= (unsigned long)c[1] << 8;
+    res |= (unsigned long)c[2] << 0;
+    return (res);
+}
+
+static XSurface*
+nk_xsurf_create(Display *dpy,  int screen, Window root, unsigned int w, unsigned int h)
+{
+    XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));
+    surface->w = w;
+    surface->h = h;
+    surface->dpy = dpy;
+    surface->screen = screen;
+    surface->root = root;
+    surface->gc = XCreateGC(dpy, root, 0, NULL);
+    XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
+    surface->drawable = XCreatePixmap(dpy, root, w, h, 32);
+    return surface;
+}
+
+static void
+nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)
+{
+    if(!surf) return;
+    if (surf->w == w && surf->h == h) return;
+    surf->w = w; surf->h = h;
+    if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);
+    surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,
+        (unsigned int)DefaultDepth(surf->dpy, surf->screen));
+}
+
+static void
+nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)
+{
+    XRectangle clip_rect;
+    clip_rect.x = (short)(x-1);
+    clip_rect.y = (short)(y-1);
+    clip_rect.width = (unsigned short)(w+2);
+    clip_rect.height = (unsigned short)(h+2);
+    XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
+}
+
+static void
+nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,
+    short y1, unsigned int line_thickness, struct nk_color col)
+{
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
+    unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    if (r == 0) {
+        XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
+    } else {
+        short xc = x + r;
+        short yc = y + r;
+        short wc = (short)(w - 2 * r);
+        short hc = (short)(h - 2 * r);
+
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+wc);
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, yc+hc, x);
+
+        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
+            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
+    }
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w,
+    unsigned short h, unsigned short r, struct nk_color col)
+{
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    if (r == 0) {
+        XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
+    } else {
+        short xc = x + r;
+        short yc = y + r;
+        short wc = (short)(w - 2 * r);
+        short hc = (short)(h - 2 * r);
+
+        XPoint pnts[12];
+        pnts[0].x = x;
+        pnts[0].y = yc;
+        pnts[1].x = xc;
+        pnts[1].y = yc;
+        pnts[2].x = xc;
+        pnts[2].y = y;
+
+        pnts[3].x = xc + wc;
+        pnts[3].y = y;
+        pnts[4].x = xc + wc;
+        pnts[4].y = yc;
+        pnts[5].x = x + w;
+        pnts[5].y = yc;
+
+        pnts[6].x = x + w;
+        pnts[6].y = yc + hc;
+        pnts[7].x = xc + wc;
+        pnts[7].y = yc + hc;
+        pnts[8].x = xc + wc;
+        pnts[8].y = y + h;
+
+        pnts[9].x = xc;
+        pnts[9].y = y + h;
+        pnts[10].x = xc;
+        pnts[10].y = yc + hc;
+        pnts[11].x = x;
+        pnts[11].y = yc + hc;
+
+        XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
+            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
+    }
+}
+
+static void
+nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,
+    short y1, short x2, short y2, struct nk_color col)
+{
+    XPoint pnts[3];
+    unsigned long c = color_from_byte(&col.r);
+    pnts[0].x = (short)x0;
+    pnts[0].y = (short)y0;
+    pnts[1].x = (short)x1;
+    pnts[1].y = (short)y1;
+    pnts[2].x = (short)x2;
+    pnts[2].y = (short)y2;
+    XSetForeground(surf->dpy, surf->gc, c);
+    XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
+}
+
+static void
+nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
+    short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+    XPoint pnts[3];
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_polygon(XSurface *surf,  const struct nk_vec2i *pnts, int count,
+    struct nk_color col)
+{
+    int i = 0;
+    #define MAX_POINTS 64
+    XPoint xpnts[MAX_POINTS];
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    for (i = 0; i < count && i < MAX_POINTS; ++i) {
+        xpnts[i].x = pnts[i].x;
+        xpnts[i].y = pnts[i].y;
+    }
+    XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);
+    #undef MAX_POINTS
+}
+
+static void
+nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
+    unsigned short line_thickness, struct nk_color col)
+{
+    int i = 0;
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    for (i = 1; i < count; ++i)
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,
+    int count, unsigned short line_thickness, struct nk_color col)
+{
+    int i = 0;
+    unsigned long c = color_from_byte(&col.r);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    XSetForeground(surf->dpy, surf->gc, c);
+    for (i = 0; i < count-1; ++i)
+        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,
+    unsigned short h, struct nk_color col)
+{
+    unsigned long c = color_from_byte(&col.r);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
+        (unsigned)w, (unsigned)h, 0, 360 * 64);
+}
+
+static void
+nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
+    unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+    unsigned long c = color_from_byte(&col.r);
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    XSetForeground(surf->dpy, surf->gc, c);
+    XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
+        (unsigned)w, (unsigned)h, 0, 360 * 64);
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
+    struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+    unsigned int num_segments, unsigned short line_thickness, struct nk_color col)
+{
+    unsigned int i_step;
+    float t_step;
+    struct nk_vec2i last = p1;
+
+    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+    num_segments = MAX(num_segments, 1);
+    t_step = 1.0f/(float)num_segments;
+    for (i_step = 1; i_step <= num_segments; ++i_step) {
+        float t = t_step * (float)i_step;
+        float u = 1.0f - t;
+        float w1 = u*u*u;
+        float w2 = 3*u*u*t;
+        float w3 = 3*u*t*t;
+        float w4 = t * t *t;
+        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
+        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
+        nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);
+        last.x = (short)x; last.y = (short)y;
+    }
+    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
+    const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+    int tx, ty;
+    unsigned long bg = color_from_byte(&cbg.r);
+    unsigned long fg = color_from_byte(&cfg.r);
+
+    XSetForeground(surf->dpy, surf->gc, bg);
+    XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
+    if(!text || !font || !len) return;
+
+    tx = (int)x;
+    ty = (int)y + font->ascent;
+    XSetForeground(surf->dpy, surf->gc, fg);
+    if(font->set)
+        XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
+    else
+        XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
+}
+
+static void
+nk_xsurf_clear(XSurface *surf, unsigned long color)
+{
+    XSetForeground(surf->dpy, surf->gc, color);
+    XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
+}
+
+static void
+nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h)
+{
+    XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0);
+}
+
+static void
+nk_xsurf_del(XSurface *surf)
+{
+    XFreePixmap(surf->dpy, surf->drawable);
+    XFreeGC(surf->dpy, surf->gc);
+    free(surf);
+}
+
+XFont*
+nk_xfont_create(Display *dpy, const char *name)
+{
+    int n;
+    char *def, **missing;
+    XFont *font = (XFont*)calloc(1, sizeof(XFont));
+    font->set = XCreateFontSet(dpy, name, &missing, &n, &def);
+    if(missing) {
+        while(n--)
+            fprintf(stderr, "missing fontset: %s\n", missing[n]);
+        XFreeStringList(missing);
+    }
+
+    if(font->set) {
+        XFontStruct **xfonts;
+        char **font_names;
+        XExtentsOfFontSet(font->set);
+        n = XFontsOfFontSet(font->set, &xfonts, &font_names);
+        while(n--) {
+            font->ascent = MAX(font->ascent, (*xfonts)->ascent);
+            font->descent = MAX(font->descent,(*xfonts)->descent);
+            xfonts++;
+        }
+    } else {
+        if(!(font->xfont = XLoadQueryFont(dpy, name))
+        && !(font->xfont = XLoadQueryFont(dpy, "fixed"))) {
+            free(font);
+            return 0;
+        }
+        font->ascent = font->xfont->ascent;
+        font->descent = font->xfont->descent;
+    }
+    font->height = font->ascent + font->descent;
+    return font;
+}
+
+static float
+nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+    XFont *font = (XFont*)handle.ptr;
+    XRectangle r;
+    if(!font || !text)
+        return 0;
+
+    if(font->set) {
+        XmbTextExtents(font->set, (const char*)text, len, NULL, &r);
+        return (float)r.width;
+    } else{
+        int w = XTextWidth(font->xfont, (const char*)text, len);
+        return (float)w;
+    }
+}
+
+void
+nk_xfont_del(Display *dpy, XFont *font)
+{
+    if(!font) return;
+    if(font->set)
+        XFreeFontSet(dpy, font->set);
+    else
+        XFreeFont(dpy, font->xfont);
+    free(font);
+}
+
+NK_API struct nk_context*
+nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root,
+    unsigned int w, unsigned int h)
+{
+    struct nk_user_font font;
+    font.userdata = nk_handle_ptr(xfont);
+    font.height = (float)xfont->height;
+    font.width = nk_xfont_get_text_width;
+
+    if (!setlocale(LC_ALL,"")) return 0;
+    if (!XSupportsLocale()) return 0;
+    if (!XSetLocaleModifiers("@im=none")) return 0;
+
+    xlib.surf = nk_xsurf_create(dpy, screen, root, w, h);
+    nk_init_default(&xlib.ctx, &font);
+    return &xlib.ctx;
+}
+
+NK_API void
+nk_xlib_set_font(XFont *xfont)
+{
+    struct nk_user_font font;
+    font.userdata = nk_handle_ptr(xfont);
+    font.height = (float)xfont->height;
+    font.width = nk_xfont_get_text_width;
+    nk_style_set_font(&xlib.ctx, &font);
+}
+
+NK_API void
+nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
+{
+    struct nk_context *ctx = &xlib.ctx;
+    if (evt->type == KeyPress || evt->type == KeyRelease)
+    {
+        /* Key handler */
+        int ret, down = (evt->type == KeyPress);
+        KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
+        if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
+        else if (*code == XK_Delete)    nk_input_key(ctx, NK_KEY_DEL, down);
+        else if (*code == XK_Return)    nk_input_key(ctx, NK_KEY_ENTER, down);
+        else if (*code == XK_Tab)       nk_input_key(ctx, NK_KEY_TAB, down);
+        else if (*code == XK_Left)      nk_input_key(ctx, NK_KEY_LEFT, down);
+        else if (*code == XK_Right)     nk_input_key(ctx, NK_KEY_RIGHT, down);
+        else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+        else if (*code == XK_Home)  nk_input_key(ctx, NK_KEY_TEXT_START, down);
+        else if (*code == XK_End)  nk_input_key(ctx, NK_KEY_TEXT_END, down);
+        else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
+        else {
+            if (*code == 'c' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_COPY, down);
+            else if (*code == 'v' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_PASTE, down);
+            else if (*code == 'x' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_CUT, down);
+            else if (*code == 'z' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
+            else if (*code == 'r' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
+            else if (*code == XK_Left && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else if (*code == XK_Right && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else if (*code == 'b' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
+            else if (*code == 'e' && (evt->xkey.state & ControlMask))
+                nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
+            else if (!down) {
+                char buf[32];
+                if ((*code >= 'a' && *code <= 'z') || (*code >= 'A' && *code <= 'Z')) {
+                    KeySym keysym = 0;
+                    if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+                        nk_input_glyph(ctx, buf);
+                }
+            }
+        }
+        XFree(code);
+    } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
+        /* Button handler */
+        int down = (evt->type == ButtonPress);
+        const int x = evt->xbutton.x, y = evt->xbutton.y;
+        if (evt->xbutton.button == Button1)
+            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        if (evt->xbutton.button == Button2)
+            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+        else if (evt->xbutton.button == Button3)
+            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+        else if (evt->xbutton.button == Button4)
+            nk_input_scroll(ctx, 1.0f);
+        else if (evt->xbutton.button == Button5)
+            nk_input_scroll(ctx, -1.0f);
+
+    } else if (evt->type == MotionNotify) {
+        /* Mouse motion handler */
+        const int x = evt->xmotion.x, y = evt->xmotion.y;
+        nk_input_motion(ctx, x, y);
+    } else if (evt->type == Expose || evt->type == ConfigureNotify) {
+        /* Window resize handler */
+        unsigned int width, height;
+        XWindowAttributes attr;
+        XGetWindowAttributes(dpy, win, &attr);
+        width = (unsigned int)attr.width;
+        height = (unsigned int)attr.height;
+        nk_xsurf_resize(xlib.surf, width, height);
+    } else if (evt->type == KeymapNotify)
+        XRefreshKeyboardMapping(&evt->xmapping);
+}
+
+NK_API void
+nk_xlib_shutdown(void)
+{
+    nk_xsurf_del(xlib.surf);
+    nk_free(&xlib.ctx);
+}
+
+NK_API void
+nk_xlib_render(Drawable screen, struct nk_color clear)
+{
+    const struct nk_command *cmd;
+    struct nk_context *ctx = &xlib.ctx;
+    XSurface *surf = xlib.surf;
+
+    nk_xsurf_clear(xlib.surf, color_from_byte(&clear.r));
+    nk_foreach(cmd, &xlib.ctx)
+    {
+        switch (cmd->type) {
+        case NK_COMMAND_NOP: break;
+        case NK_COMMAND_SCISSOR: {
+            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+            nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h);
+        } break;
+        case NK_COMMAND_LINE: {
+            const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+            nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x,
+                l->end.y, l->line_thickness, l->color);
+        } break;
+        case NK_COMMAND_RECT: {
+            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+            nk_xsurf_stroke_rect(surf, r->x, r->y, r->w, r->h,
+                (unsigned short)r->rounding, r->line_thickness, r->color);
+        } break;
+        case NK_COMMAND_RECT_FILLED: {
+            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+            nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h,
+                (unsigned short)r->rounding, r->color);
+        } break;
+        case NK_COMMAND_CIRCLE: {
+            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+            nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
+        } break;
+        case NK_COMMAND_CIRCLE_FILLED: {
+            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+            nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color);
+        } break;
+        case NK_COMMAND_TRIANGLE: {
+            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+            nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
+                t->c.x, t->c.y, t->line_thickness, t->color);
+        } break;
+        case NK_COMMAND_TRIANGLE_FILLED: {
+            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+            nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
+                t->c.x, t->c.y, t->color);
+        } break;
+        case NK_COMMAND_POLYGON: {
+            const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
+            nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color);
+        } break;
+        case NK_COMMAND_POLYGON_FILLED: {
+            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+            nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color);
+        } break;
+        case NK_COMMAND_POLYLINE: {
+            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+            nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color);
+        } break;
+        case NK_COMMAND_TEXT: {
+            const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+            nk_xsurf_draw_text(surf, t->x, t->y, t->w, t->h,
+                (const char*)t->string, t->length,
+                (XFont*)t->font->userdata.ptr,
+                t->background, t->foreground);
+        } break;
+        case NK_COMMAND_CURVE: {
+            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+            nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1],
+                q->end, 22, q->line_thickness, q->color);
+        } break;
+        case NK_COMMAND_RECT_MULTI_COLOR:
+        case NK_COMMAND_IMAGE:
+        case NK_COMMAND_ARC:
+        case NK_COMMAND_ARC_FILLED:
+        default: break;
+        }
+    }
+    nk_clear(ctx);
+    nk_xsurf_blit(screen, surf, surf->w, surf->h);
+}
+

+ 17 - 0
demo/x11/nuklear_xlib.h

@@ -0,0 +1,17 @@
+#ifndef NK_XLIB_H_
+#define NK_XLIB_H_
+
+#include "../../nuklear.h"
+
+typedef struct XFont XFont;
+NK_API struct nk_context* nk_xlib_init(XFont *font, Display *dpy, int screen, Window root, unsigned int w, unsigned int h);
+NK_API void nk_xlib_set_font(XFont *font);
+NK_API void nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt);
+NK_API void nk_xlib_render(Drawable screen, struct nk_color clear);
+NK_API void nk_xlib_shutdown(void);
+
+/* font */
+NK_API XFont* nk_xfont_create(Display *dpy, const char *name);
+NK_API void nk_xfont_del(Display *dpy, XFont *font);
+
+#endif

+ 0 - 794
demo/x11/xlib.c

@@ -1,794 +0,0 @@
-/*
-    Copyright (c) 2016 Micha Mettke
-
-    This software is provided 'as-is', without any express or implied
-    warranty.  In no event will the authors be held liable for any damages
-    arising from the use of this software.
-
-    Permission is granted to anyone to use this software for any purpose,
-    including commercial applications, and to alter it and redistribute it
-    freely, subject to the following restrictions:
-
-    1.  The origin of this software must not be misrepresented; you must not
-        claim that you wrote the original software. If you use this software
-        in a product, an acknowledgment in the product documentation would be
-        appreciated but is not required.
-    2.  Altered source versions must be plainly marked as such, and must not be
-        misrepresented as being the original software.
-    3.  This notice may not be removed or altered from any source distribution.
-*/
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <math.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xresource.h>
-#include <X11/Xlocale.h>
-
-/* macros */
-#define DTIME       16
-#include "../../zahnrad.h"
-
-#define DEMO_DO_NOT_DRAW_IMAGES
-#define DEMO_DO_NOT_USE_COLOR_PICKER
-#include "../demo.c"
-
-typedef struct XFont XFont;
-typedef struct XSurface XSurface;
-typedef struct XWindow XWindow;
-
-struct XFont {
-    int ascent;
-    int descent;
-    int height;
-    XFontSet set;
-    XFontStruct *xfont;
-};
-
-struct XSurface {
-    GC gc;
-    Display *dpy;
-    int screen;
-    Window root;
-    Drawable drawable;
-    unsigned int w, h;
-};
-
-struct XWindow {
-    Display *dpy;
-    Window root;
-    Visual *vis;
-    XFont *font;
-    XSurface *surf;
-    Colormap cmap;
-    XWindowAttributes attr;
-    XSetWindowAttributes swa;
-    Window win;
-    int screen;
-    unsigned int width;
-    unsigned int height;
-};
-
-static void
-die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    fputs("\n", stderr);
-    exit(EXIT_FAILURE);
-}
-
-static void*
-xcalloc(size_t siz, size_t n)
-{
-    void *ptr = calloc(siz, n);
-    if (!ptr) die("Out of memory\n");
-    return ptr;
-}
-
-static long
-timestamp(void)
-{
-    struct timeval tv;
-    if (gettimeofday(&tv, NULL) < 0) return 0;
-    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
-}
-
-static void
-sleep_for(long t)
-{
-    struct timespec req;
-    const time_t sec = (int)(t/1000);
-    const long ms = t - (sec * 1000);
-    req.tv_sec = sec;
-    req.tv_nsec = ms * 1000000L;
-    while(-1 == nanosleep(&req, &req));
-}
-
-static XFont*
-font_create(Display *dpy, const char *name)
-{
-    int n;
-    char *def, **missing;
-    XFont *font = (XFont*)xcalloc(1, sizeof(XFont));
-    font->set = XCreateFontSet(dpy, name, &missing, &n, &def);
-    if(missing) {
-        while(n--)
-            fprintf(stderr, "missing fontset: %s\n", missing[n]);
-        XFreeStringList(missing);
-    }
-
-    if(font->set) {
-        XFontStruct **xfonts;
-        char **font_names;
-        XExtentsOfFontSet(font->set);
-        n = XFontsOfFontSet(font->set, &xfonts, &font_names);
-        while(n--) {
-            font->ascent = MAX(font->ascent, (*xfonts)->ascent);
-            font->descent = MAX(font->descent,(*xfonts)->descent);
-            xfonts++;
-        }
-    } else {
-        if(!(font->xfont = XLoadQueryFont(dpy, name))
-        && !(font->xfont = XLoadQueryFont(dpy, "fixed")))
-            die("error, cannot load font: '%s'\n", name);
-        font->ascent = font->xfont->ascent;
-        font->descent = font->xfont->descent;
-    }
-    font->height = font->ascent + font->descent;
-    return font;
-}
-
-static zr_size
-font_get_text_width(zr_handle handle, float height, const char *text, zr_size len)
-{
-    XFont *font = (XFont*)handle.ptr;
-    XRectangle r;
-    if(!font || !text)
-        return 0;
-
-    UNUSED(height);
-    if(font->set) {
-        XmbTextExtents(font->set, (const char*)text, (int)len, NULL, &r);
-        return r.width;
-    } else return (zr_size)XTextWidth(font->xfont, (const char*)text, (int)len);
-}
-
-static void
-font_del(Display *dpy, XFont *font)
-{
-    if(!font) return;
-    if(font->set)
-        XFreeFontSet(dpy, font->set);
-    else
-        XFreeFont(dpy, font->xfont);
-    free(font);
-}
-
-static unsigned long
-color_from_byte(const zr_byte *c)
-{
-    unsigned long res = 0;
-    res |= (unsigned long)c[0] << 16;
-    res |= (unsigned long)c[1] << 8;
-    res |= (unsigned long)c[2] << 0;
-    return (res);
-}
-
-static void
-color_to_byte(unsigned char *c, unsigned long pixel)
-{
-    c[0] = (pixel & ((unsigned long)0xFF << 16)) >> 16;
-    c[1] = (pixel & ((unsigned long)0xFF << 8)) >> 8;
-    c[2] = (pixel & ((unsigned long)0xFF << 0)) >> 0;
-    c[3] = (pixel & ((unsigned long)0xFF << 24)) >> 24;
-}
-
-static XSurface*
-surface_create(Display *dpy,  int screen, Window root, unsigned int w, unsigned int h)
-{
-    XSurface *surface = (XSurface*)xcalloc(1, sizeof(XSurface));
-    surface->w = w;
-    surface->h = h;
-    surface->dpy = dpy;
-    surface->screen = screen;
-    surface->root = root;
-    surface->gc = XCreateGC(dpy, root, 0, NULL);
-    XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
-    surface->drawable = XCreatePixmap(dpy, root, w, h, 32);
-    return surface;
-}
-
-static void
-surface_resize(XSurface *surf, unsigned int w, unsigned int h)
-{
-    if(!surf) return;
-    if (surf->w == w && surf->h == h) return;
-    surf->w = w; surf->h = h;
-    if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);
-    surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,
-        (unsigned int)DefaultDepth(surf->dpy, surf->screen));
-}
-
-static void
-surface_scissor(XSurface *surf, float x, float y, float w, float h)
-{
-    XRectangle clip_rect;
-    clip_rect.x = (short)(x-1);
-    clip_rect.y = (short)(y-1);
-    clip_rect.width = (unsigned short)(w+2);
-    clip_rect.height = (unsigned short)(h+2);
-    XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
-}
-
-static void
-surface_stroke_line(XSurface *surf, short x0, short y0, short x1,
-    short y1, unsigned int line_thickness, struct zr_color col)
-{
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
-    unsigned short h, unsigned short r, unsigned short line_thickness, struct zr_color col)
-{
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    if (r == 0) {
-        XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
-    } else {
-        short xc = x + r;
-        short yc = y + r;
-        short wc = (short)(w - 2 * r);
-        short hc = (short)(h - 2 * r);
-
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+wc);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, yc+hc, x);
-
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
-            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
-            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
-    }
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_fill_rect(XSurface* surf, short x, short y, unsigned short w,
-    unsigned short h, unsigned short r, struct zr_color col)
-{
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    if (r == 0) {
-        XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
-    } else {
-        short xc = x + r;
-        short yc = y + r;
-        short wc = (short)(w - 2 * r);
-        short hc = (short)(h - 2 * r);
-
-        XPoint pnts[12];
-        pnts[0].x = x;
-        pnts[0].y = yc;
-        pnts[1].x = xc;
-        pnts[1].y = yc;
-        pnts[2].x = xc;
-        pnts[2].y = y;
-
-        pnts[3].x = xc + wc;
-        pnts[3].y = y;
-        pnts[4].x = xc + wc;
-        pnts[4].y = yc;
-        pnts[5].x = x + w;
-        pnts[5].y = yc;
-
-        pnts[6].x = x + w;
-        pnts[6].y = yc + hc;
-        pnts[7].x = xc + wc;
-        pnts[7].y = yc + hc;
-        pnts[8].x = xc + wc;
-        pnts[8].y = y + h;
-
-        pnts[9].x = xc;
-        pnts[9].y = y + h;
-        pnts[10].x = xc;
-        pnts[10].y = yc + hc;
-        pnts[11].x = x;
-        pnts[11].y = yc + hc;
-
-        XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
-            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
-            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
-    }
-}
-
-static void
-surface_fill_triangle(XSurface *surf, short x0, short y0, short x1,
-    short y1, short x2, short y2, struct zr_color col)
-{
-    XPoint pnts[3];
-    unsigned long c = color_from_byte(&col.r);
-    pnts[0].x = (short)x0;
-    pnts[0].y = (short)y0;
-    pnts[1].x = (short)x1;
-    pnts[1].y = (short)y1;
-    pnts[2].x = (short)x2;
-    pnts[2].y = (short)y2;
-    XSetForeground(surf->dpy, surf->gc, c);
-    XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
-}
-
-static void
-surface_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
-    short y1, short x2, short y2, unsigned short line_thickness, struct zr_color col)
-{
-    XPoint pnts[3];
-    unsigned long c = color_from_byte(&col.r);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);
-    XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);
-    XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_fill_polygon(XSurface *surf,  const struct zr_vec2i *pnts, int count,
-    struct zr_color col)
-{
-    int i = 0;
-    #define MAX_POINTS 64
-    XPoint xpnts[MAX_POINTS];
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    for (i = 0; i < count && i < MAX_POINTS; ++i) {
-        xpnts[i].x = pnts[i].x;
-        xpnts[i].y = pnts[i].y;
-    }
-    XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);
-    #undef MAX_POINTS
-}
-
-static void
-surface_stroke_polygon(XSurface *surf, const struct zr_vec2i *pnts, int count,
-    unsigned short line_thickness, struct zr_color col)
-{
-    int i = 0;
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    for (i = 1; i < count; ++i)
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
-    XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_stroke_polyline(XSurface *surf, const struct zr_vec2i *pnts,
-    int count, unsigned short line_thickness, struct zr_color col)
-{
-    int i = 0;
-    unsigned long c = color_from_byte(&col.r);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    XSetForeground(surf->dpy, surf->gc, c);
-    for (i = 0; i < count-1; ++i)
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_fill_circle(XSurface *surf, short x, short y, unsigned short w,
-    unsigned short h, struct zr_color col)
-{
-    unsigned long c = color_from_byte(&col.r);
-    XSetForeground(surf->dpy, surf->gc, c);
-    XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
-        (unsigned)w, (unsigned)h, 0, 360 * 64);
-}
-
-static void
-surface_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
-    unsigned short h, unsigned short line_thickness, struct zr_color col)
-{
-    unsigned long c = color_from_byte(&col.r);
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    XSetForeground(surf->dpy, surf->gc, c);
-    XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
-        (unsigned)w, (unsigned)h, 0, 360 * 64);
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_stroke_curve(XSurface *surf, struct zr_vec2i p1,
-    struct zr_vec2i p2, struct zr_vec2i p3, struct zr_vec2i p4,
-    unsigned int num_segments, unsigned short line_thickness, struct zr_color col)
-{
-    unsigned int i_step;
-    float t_step;
-    struct zr_vec2i last = p1;
-
-    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    num_segments = MAX(num_segments, 1);
-    t_step = 1.0f/(float)num_segments;
-    for (i_step = 1; i_step <= num_segments; ++i_step) {
-        float t = t_step * (float)i_step;
-        float u = 1.0f - t;
-        float w1 = u*u*u;
-        float w2 = 3*u*u*t;
-        float w3 = 3*u*t*t;
-        float w4 = t * t *t;
-        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
-        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
-        surface_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);
-        last.x = (short)x; last.y = (short)y;
-    }
-    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
-}
-
-static void
-surface_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
-    const char *text, size_t len, XFont *font, struct zr_color cbg, struct zr_color cfg)
-{
-    int tx, ty, th;
-    unsigned long bg = color_from_byte(&cbg.r);
-    unsigned long fg = color_from_byte(&cfg.r);
-
-    XSetForeground(surf->dpy, surf->gc, bg);
-    XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
-    if(!text || !font || !len) return;
-
-    tx = (int)x;
-    th = font->ascent + font->descent;
-    ty = (int)y + font->ascent;
-    XSetForeground(surf->dpy, surf->gc, fg);
-    if(font->set)
-        XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
-    else
-        XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
-}
-
-static void
-surface_clear(XSurface *surf, unsigned long color)
-{
-    XSetForeground(surf->dpy, surf->gc, color);
-    XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
-}
-
-static void
-surface_blit(XSurface *dst_surf, XSurface *src_surf,
-    int dst_x, int dst_y, int dst_w, int dst_h,
-    int src_x, int src_y, int src_w, int src_h)
-{
-    GC gc;
-    XImage *dst, *src;
-    XGCValues gcvalues;
-    int x = 0, y = 0;
-
-    /*@optimize: there is probably a more performant way to do this since this is slow as FUCK */
-    src = XGetImage(src_surf->dpy, src_surf->drawable, 0, 0, src_surf->w, src_surf->h, AllPlanes, ZPixmap);
-    dst = XGetImage(dst_surf->dpy, dst_surf->drawable, 0, 0, dst_surf->w, dst_surf->h, AllPlanes, ZPixmap);
-    for (y = 0; y < dst_h; ++y) {
-        int dst_off_y = dst_y + y;
-        int src_off_y = src_y + (int)((float)y * (float)src_h/(float)dst_h);
-        for (x = 0; x < dst_w; ++x) {
-            unsigned long dpx, spx, pixel;
-            struct zr_color dst_col_b, src_col_b, res;
-            float dst_col[4], src_col[4], res_col[4];
-            int dst_off_x = dst_x + x;
-            int src_off_x = src_x + (int)((float)x * (float)src_w/(float)dst_w);
-
-            /* acquire both source and destination pixel */
-            spx = XGetPixel(src, src_off_x, src_off_y);
-            dpx = XGetPixel(dst, dst_off_x, dst_off_y);
-
-            /* convert from 32-bit integer to byte */
-            color_to_byte(&dst_col_b.r, dpx);
-            color_to_byte(&src_col_b.r, spx);
-
-            /* convert from byte to float */
-            zr_color_f(&dst_col[0], &dst_col[1], &dst_col[2], &dst_col[3], dst_col_b);
-            zr_color_f(&src_col[0], &src_col[1], &src_col[2], &src_col[3], src_col_b);
-
-            /* perform simple alpha-blending */
-            res_col[0] = (1.0f - src_col[3]) * dst_col[0] + src_col[3] * src_col[0];
-            res_col[1] = (1.0f - src_col[3]) * dst_col[1] + src_col[3] * src_col[1];
-            res_col[2] = (1.0f - src_col[3]) * dst_col[2] + src_col[3] * src_col[2];
-            res_col[3] = 255;
-
-            /* convert from float to byte */
-            res = zr_rgb_f(res_col[0], res_col[1], res_col[2]);
-            pixel = color_from_byte(&res.r);
-
-            /* finally write pixel to surface */
-            XPutPixel(dst, dst_off_x, dst_off_y, pixel);
-        }
-    }
-    gc = XCreateGC(dst_surf->dpy, dst_surf->drawable, 0, &gcvalues);
-    XPutImage(dst_surf->dpy, dst_surf->drawable, gc, dst, 0, 0, 0, 0,
-        (unsigned int)dst_surf->w, (unsigned int)dst_surf->h);
-    XDestroyImage(src);
-    XDestroyImage(dst);
-}
-
-static void
-surface_blit_to_screen(Drawable target, XSurface *surf, unsigned int width, unsigned int height)
-{
-    XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, width, height, 0, 0);
-}
-
-static void
-surface_del(XSurface *surf)
-{
-    XFreePixmap(surf->dpy, surf->drawable);
-    XFreeGC(surf->dpy, surf->gc);
-    free(surf);
-}
-
-static void
-input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down)
-{
-    int ret;
-    KeySym *code = XGetKeyboardMapping(xw->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
-    if (*code == XK_Shift_L || *code == XK_Shift_R)
-        zr_input_key(ctx, ZR_KEY_SHIFT, down);
-    else if (*code == XK_Delete)
-        zr_input_key(ctx, ZR_KEY_DEL, down);
-    else if (*code == XK_Return)
-        zr_input_key(ctx, ZR_KEY_ENTER, down);
-    else if (*code == XK_Tab) {
-        zr_input_key(ctx, ZR_KEY_TAB, down);
-    } else if (*code == XK_space && !down)
-        zr_input_char(ctx, ' ');
-    else if (*code == XK_Left)
-        zr_input_key(ctx, ZR_KEY_LEFT, down);
-    else if (*code == XK_Right)
-        zr_input_key(ctx, ZR_KEY_RIGHT, down);
-    else if (*code == XK_BackSpace)
-        zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
-    else {
-        if (*code == 'c' && (evt->xkey.state & ControlMask))
-            zr_input_key(ctx, ZR_KEY_COPY, down);
-        else if (*code == 'v' && (evt->xkey.state & ControlMask))
-            zr_input_key(ctx, ZR_KEY_PASTE, down);
-        else if (*code == 'x' && (evt->xkey.state & ControlMask))
-            zr_input_key(ctx, ZR_KEY_CUT, down);
-        else if (!down) {
-            KeySym keysym = 0;
-            char buf[32];
-            XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL);
-            zr_input_glyph(ctx, buf);
-        }
-    }
-    XFree(code);
-}
-
-static void
-input_motion(struct zr_context *ctx, XEvent *evt)
-{
-    const int x = evt->xmotion.x;
-    const int y = evt->xmotion.y;
-    zr_input_motion(ctx, x, y);
-}
-
-static void
-input_button(struct zr_context *ctx, XEvent *evt, int down)
-{
-    const int x = evt->xbutton.x;
-    const int y = evt->xbutton.y;
-    if (evt->xbutton.button == Button1)
-        zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
-    if (evt->xbutton.button == Button2)
-        zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
-    else if (evt->xbutton.button == Button3)
-        zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
-    else if (evt->xbutton.button == Button4)
-        zr_input_scroll(ctx, 1.0f);
-    else if (evt->xbutton.button == Button5)
-        zr_input_scroll(ctx, -1.0f);
-}
-
-static void
-resize(struct XWindow *xw, XSurface *surf)
-{
-    XGetWindowAttributes(xw->dpy, xw->win, &xw->attr);
-    xw->width = (unsigned int)xw->attr.width;
-    xw->height = (unsigned int)xw->attr.height;
-    surface_resize(surf, xw->width, xw->height);
-}
-
-int
-main(int argc, char *argv[])
-{
-    long dt;
-    long started;
-    XWindow xw;
-    struct demo gui;
-    struct zr_user_font font;
-    int running = 1;
-
-    /* X11 */
-    UNUSED(argc); UNUSED(argv);
-    memset(&xw, 0, sizeof xw);
-    if (setlocale(LC_ALL, "") == NULL) return 9;
-    if (!XSupportsLocale()) return 10;
-    if (!XSetLocaleModifiers("@im=none")) return 11;
-
-    xw.dpy = XOpenDisplay(NULL);
-    xw.root = DefaultRootWindow(xw.dpy);
-    xw.screen = XDefaultScreen(xw.dpy);
-    xw.vis = XDefaultVisual(xw.dpy, xw.screen);
-    xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
-    xw.swa.colormap = xw.cmap;
-    xw.swa.event_mask =
-        ExposureMask | KeyPressMask | KeyReleaseMask |
-        ButtonPress | ButtonReleaseMask| ButtonMotionMask |
-        Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
-        PointerMotionMask | KeymapStateMask;
-    xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
-        XDefaultDepth(xw.dpy, xw.screen), InputOutput,
-        xw.vis, CWEventMask | CWColormap, &xw.swa);
-    XStoreName(xw.dpy, xw.win, "X11");
-    XMapWindow(xw.dpy, xw.win);
-
-    XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
-    xw.width = (unsigned int)xw.attr.width;
-    xw.height = (unsigned int)xw.attr.height;
-    xw.surf = surface_create(xw.dpy, xw.screen, xw.win, xw.width, xw.height);
-    xw.font = font_create(xw.dpy, "fixed");
-
-    /* GUI */
-    font.userdata = zr_handle_ptr(xw.font);
-    font.height = (float)xw.font->height;
-    font.width = font_get_text_width;
-    memset(&gui, 0, sizeof gui);
-    gui.memory = calloc(MAX_MEMORY, 1);
-    zr_init_fixed(&gui.ctx, gui.memory, MAX_MEMORY, &font);
-
-    while (running) {
-        /* Input */
-        XEvent evt;
-        started = timestamp();
-        zr_input_begin(&gui.ctx);
-        while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) {
-            if (XFilterEvent(&evt, xw.win)) continue;
-            if (evt.type == KeyPress)
-                input_key(&xw, &gui.ctx, &evt, zr_true);
-            else if (evt.type == KeyRelease)
-                input_key(&xw, &gui.ctx, &evt, zr_false);
-            else if (evt.type == ButtonPress)
-                input_button(&gui.ctx, &evt, zr_true);
-            else if (evt.type == ButtonRelease)
-                input_button(&gui.ctx, &evt, zr_false);
-            else if (evt.type == MotionNotify)
-                input_motion(&gui.ctx, &evt);
-            else if (evt.type == Expose || evt.type == ConfigureNotify)
-                resize(&xw, xw.surf);
-            else if (evt.type == KeymapNotify)
-                XRefreshKeyboardMapping(&evt.xmapping);
-        }
-        zr_input_end(&gui.ctx);
-
-        /* GUI */
-        running = run_demo(&gui);
-
-        /* Draw */
-        XClearWindow(xw.dpy, xw.win);
-        surface_clear(xw.surf, 0x00303030);
-        {
-            const struct zr_command *cmd;
-            zr_foreach(cmd, &gui.ctx) {
-                switch (cmd->type) {
-                case ZR_COMMAND_NOP: break;
-                case ZR_COMMAND_SCISSOR: {
-                    const struct zr_command_scissor *s = zr_command(scissor, cmd);
-                    surface_scissor(xw.surf, s->x, s->y, s->w, s->h);
-                } break;
-                case ZR_COMMAND_LINE: {
-                    const struct zr_command_line *l = zr_command(line, cmd);
-                    surface_stroke_line(xw.surf, l->begin.x, l->begin.y, l->end.x,
-                        l->end.y, l->line_thickness, l->color);
-                } break;
-                case ZR_COMMAND_RECT: {
-                    const struct zr_command_rect *r = zr_command(rect, cmd);
-                    surface_stroke_rect(xw.surf, r->x, r->y, r->w, r->h,
-                        (uint16_t)r->rounding, r->line_thickness, r->color);
-                } break;
-                case ZR_COMMAND_RECT_FILLED: {
-                    const struct zr_command_rect_filled *r = zr_command(rect_filled, cmd);
-                    surface_fill_rect(xw.surf, r->x, r->y, r->w, r->h,
-                        (uint16_t)r->rounding, r->color);
-                } break;
-                case ZR_COMMAND_CIRCLE: {
-                    const struct zr_command_circle *c = zr_command(circle, cmd);
-                    surface_stroke_circle(xw.surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
-                } break;
-                case ZR_COMMAND_CIRCLE_FILLED: {
-                    const struct zr_command_circle_filled *c = zr_command(circle_filled, cmd);
-                    surface_fill_circle(xw.surf, c->x, c->y, c->w, c->h, c->color);
-                } break;
-                case ZR_COMMAND_TRIANGLE: {
-                    const struct zr_command_triangle*t = zr_command(triangle, cmd);
-                    surface_stroke_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y,
-                        t->c.x, t->c.y, t->line_thickness, t->color);
-                } break;
-                case ZR_COMMAND_TRIANGLE_FILLED: {
-                    const struct zr_command_triangle_filled *t = zr_command(triangle_filled, cmd);
-                    surface_fill_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y,
-                        t->c.x, t->c.y, t->color);
-                } break;
-                case ZR_COMMAND_POLYGON: {
-                    const struct zr_command_polygon *p = zr_command(polygon, cmd);
-                    surface_stroke_polygon(xw.surf, p->points, p->point_count, p->line_thickness,p->color);
-                } break;
-                case ZR_COMMAND_POLYGON_FILLED: {
-                    const struct zr_command_polygon_filled *p = zr_command(polygon_filled, cmd);
-                    surface_fill_polygon(xw.surf, p->points, p->point_count, p->color);
-                } break;
-                case ZR_COMMAND_POLYLINE: {
-                    const struct zr_command_polyline *p = zr_command(polyline, cmd);
-                    surface_stroke_polyline(xw.surf, p->points, p->point_count, p->line_thickness, p->color);
-                } break;
-                case ZR_COMMAND_TEXT: {
-                    const struct zr_command_text *t = zr_command(text, cmd);
-                    surface_draw_text(xw.surf, t->x, t->y, t->w, t->h,
-                        (const char*)t->string, t->length,
-                        (XFont*)t->font->userdata.ptr,
-                        t->background, t->foreground);
-                } break;
-                case ZR_COMMAND_CURVE: {
-                    const struct zr_command_curve *q = zr_command(curve, cmd);
-                    surface_stroke_curve(xw.surf, q->begin, q->ctrl[0], q->ctrl[1],
-                        q->end, 22, q->line_thickness, q->color);
-                } break;
-                case ZR_COMMAND_RECT_MULTI_COLOR:
-                case ZR_COMMAND_IMAGE:
-                case ZR_COMMAND_ARC:
-                case ZR_COMMAND_ARC_FILLED:
-                default: break;
-                }
-            }
-            zr_clear(&gui.ctx);
-        }
-        surface_blit_to_screen(xw.win, xw.surf, xw.width, xw.height);
-        XFlush(xw.dpy);
-
-        /* Timing */
-        dt = timestamp() - started;
-        if (dt < DTIME)
-            sleep_for(DTIME - dt);
-    }
-    free(gui.memory);
-    font_del(xw.dpy, xw.font);
-    surface_del(xw.surf);
-    XUnmapWindow(xw.dpy, xw.win);
-    XFreeColormap(xw.dpy, xw.cmap);
-    XDestroyWindow(xw.dpy, xw.win);
-    XCloseDisplay(xw.dpy);
-    return 0;
-}
-

+ 34 - 0
example/Makefile

@@ -0,0 +1,34 @@
+# Compiler
+CC = clang
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+LIBS = -lglfw -lGL -lm -lGLU -lGLEW
+endif
+
+all: node_editor file_browser overview extended
+node_editor:
+	@mkdir -p bin
+	rm -f bin/node_editor $(OBJS)
+	$(CC) $(CFLAGS) -o bin/node_editor node_editor.c $(LIBS)
+
+file_browser:
+	@mkdir -p bin
+	rm -f bin/file_browser $(OBJS)
+	$(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS)
+
+overview:
+	@mkdir -p bin
+	rm -f bin/overview $(OBJS)
+	$(CC) $(CFLAGS) -o bin/overview overview.c $(LIBS)
+
+extended:
+	@mkdir -p bin
+	rm -f bin/extended $(OBJS)
+	$(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS)
+

+ 882 - 0
example/extended.c

@@ -0,0 +1,882 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+struct icons {
+    struct nk_image unchecked;
+    struct nk_image checked;
+    struct nk_image rocket;
+    struct nk_image cloud;
+    struct nk_image pen;
+    struct nk_image play;
+    struct nk_image pause;
+    struct nk_image stop;
+    struct nk_image prev;
+    struct nk_image next;
+    struct nk_image tools;
+    struct nk_image dir;
+    struct nk_image copy;
+    struct nk_image convert;
+    struct nk_image del;
+    struct nk_image edit;
+    struct nk_image images[9];
+    struct nk_image menu[6];
+};
+
+/* ===============================================================
+ *
+ *                          CUSTOM WIDGET
+ *
+ * ===============================================================*/
+static int
+ui_piemenu(struct nk_context *ctx, struct nk_vec2 pos, float radius,
+            struct nk_image *icons, int item_count)
+{
+    int ret = -1;
+    struct nk_rect total_space;
+    struct nk_panel popup;
+    struct nk_rect bounds;
+    int active_item = 0;
+
+    /* pie menu popup */
+    struct nk_color border = ctx->style.window.border_color;
+    struct nk_style_item background = ctx->style.window.fixed_background;
+    ctx->style.window.fixed_background = nk_style_item_hide();
+    ctx->style.window.border_color = nk_rgba(0,0,0,0);
+
+    total_space  = nk_window_get_content_region(ctx);
+    nk_popup_begin(ctx, &popup,  NK_POPUP_STATIC, "piemenu", NK_WINDOW_NO_SCROLLBAR,
+        nk_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y,
+        2*radius,2*radius));
+
+    total_space = nk_window_get_content_region(ctx);
+    nk_layout_row_dynamic(ctx, total_space.h, 1);
+    {
+        int i = 0;
+        struct nk_command_buffer* out = nk_window_get_canvas(ctx);
+        const struct nk_input *in = &ctx->input;
+        {
+            /* allocate complete popup space for the menu */
+            enum nk_widget_layout_states state;
+            total_space = nk_window_get_content_region(ctx);
+            total_space.x = total_space.y = 0;
+            state = nk_widget(&bounds, ctx);
+        }
+
+        /* outer circle */
+        nk_fill_circle(out, bounds, nk_rgb(50,50,50));
+        {
+            /* circle buttons */
+            float step = (2 * 3.141592654f) / (float)(MAX(1,item_count));
+            float a_min = 0; float a_max = step;
+
+            struct nk_vec2 center = nk_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f);
+            struct nk_vec2 drag = nk_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y);
+            float angle = (float)atan2(drag.y, drag.x);
+            if (angle < -0.0f) angle += 2.0f * 3.141592654f;
+            active_item = (int)(angle/step);
+
+            for (i = 0; i < item_count; ++i) {
+                struct nk_rect content;
+                float rx, ry, dx, dy, a;
+                nk_fill_arc(out, center.x, center.y, (bounds.w/2.0f),
+                    a_min, a_max, (active_item == i) ? nk_rgb(45,100,255): nk_rgb(60,60,60));
+
+                /* seperator line */
+                rx = bounds.w/2.0f; ry = 0;
+                dx = rx * (float)cos(a_min) - ry * (float)sin(a_min);
+                dy = rx * (float)sin(a_min) + ry * (float)cos(a_min);
+                nk_stroke_line(out, center.x, center.y,
+                    center.x + dx, center.y + dy, 1.0f, nk_rgb(50,50,50));
+
+                /* button content */
+                a = a_min + (a_max - a_min)/2.0f;
+                rx = bounds.w/2.5f; ry = 0;
+                content.w = 30; content.h = 30;
+                content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f);
+                content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f);
+                nk_draw_image(out, content, &icons[i]);
+                a_min = a_max; a_max += step;
+            }
+        }
+        {
+            /* inner circle */
+            struct nk_rect inner;
+            inner.x = bounds.x + bounds.w/2 - bounds.w/4;
+            inner.y = bounds.y + bounds.h/2 - bounds.h/4;
+            inner.w = bounds.w/2; inner.h = bounds.h/2;
+            nk_fill_circle(out, inner, nk_rgb(45,45,45));
+
+            /* active icon content */
+            bounds.w = inner.w / 2.0f;
+            bounds.h = inner.h / 2.0f;
+            bounds.x = inner.x + inner.w/2 - bounds.w/2;
+            bounds.y = inner.y + inner.h/2 - bounds.h/2;
+            nk_draw_image(out, bounds, &icons[active_item]);
+        }
+    }
+    nk_layout_space_end(ctx);
+    nk_popup_end(ctx);
+
+    ctx->style.window.fixed_background = background;
+    ctx->style.window.border_color = border;
+
+    if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT))
+        return active_item;
+    else return ret;
+}
+
+/* ===============================================================
+ *
+ *                          GRID
+ *
+ * ===============================================================*/
+static void
+grid_demo(struct nk_context *ctx)
+{
+    static char text[3][64];
+    static int text_len[3];
+    static const char *items[] = {"Item 0","item 1","item 2"};
+    static int selected_item = 0;
+    static int check = 1;
+    struct nk_panel layout;
+
+    int i;
+    struct nk_panel combo;
+    ctx->style.font.height = 20;
+    if (nk_begin(ctx, &layout, "Grid Demo", nk_rect(600, 350, 275, 250),
+        NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|
+        NK_WINDOW_BORDER_HEADER|NK_WINDOW_NO_SCROLLBAR))
+    {
+        ctx->style.font.height = 18;
+        nk_layout_row_dynamic(ctx, 30, 2);
+        nk_label(ctx, "Floating point:", NK_TEXT_RIGHT);
+        nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float);
+        nk_label(ctx, "Hexadeximal:", NK_TEXT_RIGHT);
+        nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex);
+        nk_label(ctx, "Binary:", NK_TEXT_RIGHT);
+        nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary);
+        nk_label(ctx, "Checkbox:", NK_TEXT_RIGHT);
+        nk_checkbox_label(ctx, "Check me", &check);
+        nk_label(ctx, "Combobox:", NK_TEXT_RIGHT);
+
+        if (nk_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
+            nk_layout_row_dynamic(ctx, 30, 1);
+            for (i = 0; i < 3; ++i)
+                if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
+                    selected_item = i;
+            nk_combo_end(ctx);
+        }
+    }
+    nk_end(ctx);
+    ctx->style.font.height = 14;
+}
+
+/* ===============================================================
+ *
+ *                          BUTTON DEMO
+ *
+ * ===============================================================*/
+static void
+ui_header(struct nk_context *ctx, const char *title)
+{
+    ctx->style.font.height = 18;
+    nk_layout_row_dynamic(ctx, 20, 1);
+    nk_label(ctx, title, NK_TEXT_LEFT);
+}
+
+static void
+ui_widget(struct nk_context *ctx, float height, float font_height)
+{
+    static const float ratio[] = {0.15f, 0.85f};
+    ctx->style.font.height = font_height;
+    nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);
+    nk_spacing(ctx, 1);
+}
+
+static void
+ui_widget_centered(struct nk_context *ctx, float height, float font_height)
+{
+    static const float ratio[] = {0.15f, 0.50f, 0.35f};
+    ctx->style.font.height = font_height;
+    nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio);
+    nk_spacing(ctx, 1);
+}
+
+static void
+button_demo(struct nk_context *ctx, struct icons *img)
+{
+    struct nk_panel layout;
+    struct nk_panel menu;
+    static int option = 1;
+    static int toggle0 = 1;
+    static int toggle1 = 0;
+    static int toggle2 = 1;
+
+    ctx->style.font.height = 20;
+    nk_begin(ctx, &layout, "Button Demo", nk_rect(50,50,255,610),
+        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_BORDER_HEADER|NK_WINDOW_TITLE);
+
+    /*------------------------------------------------
+     *                  MENU
+     *------------------------------------------------*/
+    nk_menubar_begin(ctx);
+    {
+        /* toolbar */
+        nk_layout_row_static(ctx, 40, 40, 4);
+        if (nk_menu_begin_image(ctx, &menu, "Music", img->play, 120))
+        {
+            /* settings */
+            nk_layout_row_dynamic(ctx, 25, 1);
+            nk_menu_item_image_label(ctx, img->play, "Play", NK_TEXT_RIGHT);
+            nk_menu_item_image_label(ctx, img->stop, "Stop", NK_TEXT_RIGHT);
+            nk_menu_item_image_label(ctx, img->pause, "Pause", NK_TEXT_RIGHT);
+            nk_menu_item_image_label(ctx, img->next, "Next", NK_TEXT_RIGHT);
+            nk_menu_item_image_label(ctx, img->prev, "Prev", NK_TEXT_RIGHT);
+            nk_menu_end(ctx);
+        }
+        nk_button_image(ctx, img->tools, NK_BUTTON_DEFAULT);
+        nk_button_image(ctx, img->cloud, NK_BUTTON_DEFAULT);
+        nk_button_image(ctx, img->pen, NK_BUTTON_DEFAULT);
+    }
+    nk_menubar_end(ctx);
+
+    /*------------------------------------------------
+     *                  BUTTON
+     *------------------------------------------------*/
+    ui_header(ctx, "Push buttons");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_label(ctx, "Push me", NK_BUTTON_DEFAULT))
+        fprintf(stdout, "pushed!\n");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_image_label(ctx, img->rocket, "Styled", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
+        fprintf(stdout, "rocket!\n");
+
+    /*------------------------------------------------
+     *                  REPEATER
+     *------------------------------------------------*/
+    ui_header(ctx, "Repeater");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_label(ctx, "Press me", NK_BUTTON_REPEATER))
+        fprintf(stdout, "pressed!\n");
+
+    /*------------------------------------------------
+     *                  TOGGLE
+     *------------------------------------------------*/
+    ui_header(ctx, "Toggle buttons");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_image_label(ctx, (toggle0) ? img->checked: img->unchecked,
+        "Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle0 = !toggle0;
+
+    ui_widget(ctx, 35, 22);
+    if (nk_button_image_label(ctx, (toggle1) ? img->checked: img->unchecked,
+        "Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle1 = !toggle1;
+
+    ui_widget(ctx, 35, 22);
+    if (nk_button_image_label(ctx, (toggle2) ? img->checked: img->unchecked,
+        "Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle2 = !toggle2;
+
+    /*------------------------------------------------
+     *                  RADIO
+     *------------------------------------------------*/
+    ui_header(ctx, "Radio buttons");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
+            "Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 0;
+    ui_widget(ctx, 35, 22);
+    if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
+            "Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 1;
+    ui_widget(ctx, 35, 22);
+    if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
+            "Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 2;
+
+    /*------------------------------------------------
+     *                  CONTEXTUAL
+     *------------------------------------------------*/
+    if (nk_contextual_begin(ctx, &menu, NK_WINDOW_NO_SCROLLBAR, nk_vec2(120, 200), nk_window_get_bounds(ctx))) {
+        ctx->style.font.height = 18;
+        nk_layout_row_dynamic(ctx, 25, 1);
+        if (nk_contextual_item_image_label(ctx, img->copy, "Clone", NK_TEXT_RIGHT))
+            fprintf(stdout, "pressed clone!\n");
+        if (nk_contextual_item_image_label(ctx, img->del, "Delete", NK_TEXT_RIGHT))
+            fprintf(stdout, "pressed delete!\n");
+        if (nk_contextual_item_image_label(ctx, img->convert, "Convert", NK_TEXT_RIGHT))
+            fprintf(stdout, "pressed convert!\n");
+        if (nk_contextual_item_image_label(ctx, img->edit, "Edit", NK_TEXT_RIGHT))
+            fprintf(stdout, "pressed edit!\n");
+        nk_contextual_end(ctx);
+    }
+    ctx->style.font.height = 14;
+    nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ *                          BASIC DEMO
+ *
+ * ===============================================================*/
+static void
+basic_demo(struct nk_context *ctx, struct icons *img)
+{
+    static int image_active;
+    static int check0 = 1;
+    static int check1 = 0;
+    static size_t prog = 80;
+    static int selected_item = 0;
+    static int selected_image = 3;
+    static int selected_icon = 0;
+    static const char *items[] = {"Item 0","item 1","item 2"};
+    static int piemenu_active = 0;
+    static struct nk_vec2 piemenu_pos;
+
+    int i = 0;
+    struct nk_panel layout;
+    struct nk_panel combo;
+    ctx->style.font.height = 20;
+    nk_begin(ctx, &layout, "Basic Demo", nk_rect(320, 50, 275, 610),
+        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_BORDER_HEADER|NK_WINDOW_TITLE);
+
+    /*------------------------------------------------
+     *                  POPUP BUTTON
+     *------------------------------------------------*/
+    ui_header(ctx, "Popup & Scrollbar & Images");
+    ui_widget(ctx, 35, 22);
+    if (nk_button_image_label(ctx, img->dir,
+        "Images", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
+        image_active = !image_active;
+
+    /*------------------------------------------------
+     *                  SELECTED IMAGE
+     *------------------------------------------------*/
+    ui_header(ctx, "Selected Image");
+    ui_widget_centered(ctx, 100, 22);
+    nk_image(ctx, img->images[selected_image]);
+
+    /*------------------------------------------------
+     *                  IMAGE POPUP
+     *------------------------------------------------*/
+    if (image_active) {
+        struct nk_panel popup;
+        if (nk_popup_begin(ctx, &popup, NK_POPUP_STATIC, "Image Popup", 0, nk_rect(265, 0, 320, 220))) {
+            nk_layout_row_static(ctx, 82, 82, 3);
+            for (i = 0; i < 9; ++i) {
+                if (nk_button_image(ctx, img->images[i], NK_BUTTON_DEFAULT)) {
+                    selected_image = i;
+                    image_active = 0;
+                    nk_popup_close(ctx);
+                }
+            }
+            nk_popup_end(ctx);
+        }
+    }
+    /*------------------------------------------------
+     *                  COMBOBOX
+     *------------------------------------------------*/
+    ui_header(ctx, "Combo box");
+    ui_widget(ctx, 40, 22);
+    if (nk_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
+        nk_layout_row_dynamic(ctx, 35, 1);
+        for (i = 0; i < 3; ++i)
+            if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
+                selected_item = i;
+        nk_combo_end(ctx);
+    }
+
+    ui_widget(ctx, 40, 22);
+    if (nk_combo_begin_image_label(ctx, &combo, items[selected_icon], img->images[selected_icon], 200)) {
+        nk_layout_row_dynamic(ctx, 35, 1);
+        for (i = 0; i < 3; ++i)
+            if (nk_combo_item_image_label(ctx, img->images[i], items[i], NK_TEXT_RIGHT))
+                selected_icon = i;
+        nk_combo_end(ctx);
+    }
+
+    /*------------------------------------------------
+     *                  CHECKBOX
+     *------------------------------------------------*/
+    ui_header(ctx, "Checkbox");
+    ui_widget(ctx, 30, 22);
+    nk_checkbox_label(ctx, "Flag 1", &check0);
+    ui_widget(ctx, 30, 22);
+    nk_checkbox_label(ctx, "Flag 2", &check1);
+
+    /*------------------------------------------------
+     *                  PROGRESSBAR
+     *------------------------------------------------*/
+    ui_header(ctx, "Progressbar");
+    ui_widget(ctx, 35, 22);
+    nk_progress(ctx, &prog, 100, nk_true);
+
+    /*------------------------------------------------
+     *                  PIEMENU
+     *------------------------------------------------*/
+    if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT,
+        layout.bounds,nk_true)){
+        piemenu_pos = ctx->input.mouse.pos;
+        piemenu_active = 1;
+    }
+
+    if (piemenu_active) {
+        int ret = ui_piemenu(ctx, piemenu_pos, 140, &img->menu[0], 6);
+        if (ret != -1) {
+            fprintf(stdout, "piemenu selected: %d\n", ret);
+            piemenu_active = 0;
+        }
+    }
+    ctx->style.font.height = 14;
+    nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ *                          DEVICE
+ *
+ * ===============================================================*/
+struct device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+static void
+die(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fputs("\n", stderr);
+    exit(EXIT_FAILURE);
+}
+
+static struct nk_image
+icon_load(const char *filename)
+{
+    int x,y,n;
+    GLuint tex;
+    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+    if (!data) die("[SDL]: failed to load image: %s", filename);
+
+    glGenTextures(1, &tex);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+    glGenerateMipmap(GL_TEXTURE_2D);
+    stbi_image_free(data);
+    return nk_image_id((int)tex);
+}
+
+
+static void
+device_init(struct device *dev)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+    enum nk_anti_aliasing AA)
+{
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+    /* Platform */
+    static GLFWwindow *win;
+    int width = 0, height = 0;
+
+    /* GUI */
+    struct device device;
+    struct nk_font *font;
+    struct nk_font_atlas atlas;
+    struct icons icons;
+    struct nk_context ctx;
+
+    /* GLFW */
+    glfwSetErrorCallback(error_callback);
+    if (!glfwInit()) {
+        fprintf(stdout, "[GFLW] failed to init!\n");
+        exit(1);
+    }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwMakeContextCurrent(win);
+    glfwSetWindowUserPointer(win, &ctx);
+    glfwSetCharCallback(win, text_input);
+    glfwSetScrollCallback(win, scroll_input);
+
+    /* OpenGL */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    {/* GUI */
+    device_init(&device);
+    {const void *image; int w, h;
+    const char *font_path = (argc > 1) ? argv[1]: 0;
+    nk_font_atlas_init_default(&atlas);
+    nk_font_atlas_begin(&atlas);
+    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
+    else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
+    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    device_upload_atlas(&device, image, w, h);
+    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+    nk_init_default(&ctx, &font->handle);}
+
+    /* icons */
+    glEnable(GL_TEXTURE_2D);
+    icons.unchecked = icon_load("../icon/unchecked.png");
+    icons.checked = icon_load("../icon/checked.png");
+    icons.rocket = icon_load("../icon/rocket.png");
+    icons.cloud = icon_load("../icon/cloud.png");
+    icons.pen = icon_load("../icon/pen.png");
+    icons.play = icon_load("../icon/play.png");
+    icons.pause = icon_load("../icon/pause.png");
+    icons.stop = icon_load("../icon/stop.png");
+    icons.next =  icon_load("../icon/next.png");
+    icons.prev =  icon_load("../icon/prev.png");
+    icons.tools = icon_load("../icon/tools.png");
+    icons.dir = icon_load("../icon/directory.png");
+    icons.copy = icon_load("../icon/copy.png");
+    icons.convert = icon_load("../icon/export.png");
+    icons.del = icon_load("../icon/delete.png");
+    icons.edit = icon_load("../icon/edit.png");
+    icons.menu[0] = icon_load("../icon/home.png");
+    icons.menu[1] = icon_load("../icon/phone.png");
+    icons.menu[2] = icon_load("../icon/plane.png");
+    icons.menu[3] = icon_load("../icon/wifi.png");
+    icons.menu[4] = icon_load("../icon/settings.png");
+    icons.menu[5] = icon_load("../icon/volume.png");
+
+    {int i;
+    for (i = 0; i < 9; ++i) {
+        char buffer[256];
+        sprintf(buffer, "../images/image%d.png", (i+1));
+        icons.images[i] = icon_load(buffer);
+    }}
+
+    while (!glfwWindowShouldClose(win))
+    {
+        /* Input */
+        {double x, y;
+        nk_input_begin(&ctx);
+        glfwPollEvents();
+        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
+            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+        } else {
+            nk_input_key(&ctx, NK_KEY_COPY, 0);
+            nk_input_key(&ctx, NK_KEY_PASTE, 0);
+            nk_input_key(&ctx, NK_KEY_CUT, 0);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+        }
+        glfwGetCursorPos(win, &x, &y);
+        nk_input_motion(&ctx, (int)x, (int)y);
+        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+        nk_input_end(&ctx);}
+
+        /* GUI */
+        basic_demo(&ctx, &icons);
+        button_demo(&ctx, &icons);
+        grid_demo(&ctx);
+
+        /* Draw */
+        glfwGetWindowSize(win, &width, &height);
+        glViewport(0, 0, width, height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+        device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
+        glfwSwapBuffers(win);
+    }
+
+    glDeleteTextures(1,(const GLuint*)&icons.unchecked.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.checked.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.rocket.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.cloud.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.pen.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.play.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.pause.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.stop.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.next.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.prev.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.tools.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.dir.handle.id);
+    glDeleteTextures(1,(const GLuint*)&icons.del.handle.id);
+
+    nk_font_atlas_clear(&atlas);
+    nk_free(&ctx);
+    device_shutdown(&device);
+    glfwTerminate();
+    return 0;
+}
+
+

+ 889 - 0
example/file_browser.c

@@ -0,0 +1,889 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          GUI
+ *
+ * ===============================================================*/
+struct icons {
+    struct nk_image desktop;
+    struct nk_image home;
+    struct nk_image computer;
+    struct nk_image directory;
+
+    struct nk_image default_file;
+    struct nk_image text_file;
+    struct nk_image music_file;
+    struct nk_image font_file;
+    struct nk_image img_file;
+    struct nk_image movie_file;
+};
+
+enum file_groups {
+    FILE_GROUP_DEFAULT,
+    FILE_GROUP_TEXT,
+    FILE_GROUP_MUSIC,
+    FILE_GROUP_FONT,
+    FILE_GROUP_IMAGE,
+    FILE_GROUP_MOVIE,
+    FILE_GROUP_MAX
+};
+
+enum file_types {
+    FILE_DEFAULT,
+    FILE_TEXT,
+    FILE_C_SOURCE,
+    FILE_CPP_SOURCE,
+    FILE_HEADER,
+    FILE_CPP_HEADER,
+    FILE_MP3,
+    FILE_WAV,
+    FILE_OGG,
+    FILE_TTF,
+    FILE_BMP,
+    FILE_PNG,
+    FILE_JPEG,
+    FILE_PCX,
+    FILE_TGA,
+    FILE_GIF,
+    FILE_MAX
+};
+
+struct file_group {
+    enum file_groups group;
+    const char *name;
+    struct nk_image *icon;
+};
+
+struct file {
+    enum file_types type;
+    const char *suffix;
+    enum file_groups group;
+};
+
+struct media {
+    int font;
+    int icon_sheet;
+    struct icons icons;
+    struct file_group group[FILE_GROUP_MAX];
+    struct file files[FILE_MAX];
+};
+
+#define MAX_PATH_LEN 512
+struct file_browser {
+    /* path */
+    char file[MAX_PATH_LEN];
+    char home[MAX_PATH_LEN];
+    char desktop[MAX_PATH_LEN];
+    char directory[MAX_PATH_LEN];
+
+    /* directory content */
+    char **files;
+    char **directories;
+    size_t file_count;
+    size_t dir_count;
+    struct media *media;
+};
+
+#ifdef __unix__
+#include <dirent.h>
+#include <unistd.h>
+#endif
+
+#ifndef _WIN32
+# include <pwd.h>
+#endif
+
+static void
+die(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fputs("\n", stderr);
+    exit(EXIT_FAILURE);
+}
+
+static char*
+file_load(const char* path, size_t* siz)
+{
+    char *buf;
+    FILE *fd = fopen(path, "rb");
+    if (!fd) die("Failed to open file: %s\n", path);
+    fseek(fd, 0, SEEK_END);
+    *siz = (size_t)ftell(fd);
+    fseek(fd, 0, SEEK_SET);
+    buf = (char*)calloc(*siz, 1);
+    fread(buf, *siz, 1, fd);
+    fclose(fd);
+    return buf;
+}
+
+static char*
+str_duplicate(const char *src)
+{
+    char *ret;
+    size_t len = strlen(src);
+    if (!len) return 0;
+    ret = (char*)malloc(len+1);
+    if (!ret) return 0;
+    memcpy(ret, src, len);
+    ret[len] = '\0';
+    return ret;
+}
+
+static void
+dir_free_list(char **list, size_t size)
+{
+    size_t i;
+    for (i = 0; i < size; ++i)
+        free(list[i]);
+    free(list);
+}
+
+static char**
+dir_list(const char *dir, int return_subdirs, size_t *count)
+{
+    size_t n = 0;
+    char buffer[MAX_PATH_LEN];
+    char **results = NULL;
+    const DIR *none = NULL;
+    size_t capacity = 32;
+    size_t size;
+    DIR *z;
+
+    assert(dir);
+    assert(count);
+    strncpy(buffer, dir, MAX_PATH_LEN);
+    n = strlen(buffer);
+
+    if (n > 0 && (buffer[n-1] != '/'))
+        buffer[n++] = '/';
+
+    size = 0;
+
+    z = opendir(dir);
+    if (z != none) {
+        int nonempty = 1;
+        struct dirent *data = readdir(z);
+        nonempty = (data != NULL);
+        if (!nonempty) return NULL;
+
+        do {
+            DIR *y;
+            char *p;
+            int is_subdir;
+            if (data->d_name[0] == '.')
+                continue;
+
+            strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);
+            y = opendir(buffer);
+            is_subdir = (y != NULL);
+            if (y != NULL) closedir(y);
+
+            if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){
+                if (!size) {
+                    results = (char**)calloc(sizeof(char*), capacity);
+                } else if (size >= capacity) {
+                    capacity = capacity * 2;
+                    results = (char**)realloc(results, capacity * sizeof(char*));
+                }
+                p = str_duplicate(data->d_name);
+                results[size++] = p;
+            }
+        } while ((data = readdir(z)) != NULL);
+    }
+
+    if (z) closedir(z);
+    *count = size;
+    return results;
+}
+
+static struct file_group
+FILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon)
+{
+    struct file_group fg;
+    fg.group = group;
+    fg.name = name;
+    fg.icon = icon;
+    return fg;
+}
+
+static struct file
+FILE_DEF(enum file_types type, const char *suffix, enum file_groups group)
+{
+    struct file fd;
+    fd.type = type;
+    fd.suffix = suffix;
+    fd.group = group;
+    return fd;
+}
+
+static struct nk_image*
+media_icon_for_file(struct media *media, const char *file)
+{
+    int i = 0;
+    const char *s = file;
+    char suffix[4];
+    int found = 0;
+    memset(suffix, 0, sizeof(suffix));
+
+    /* extract suffix .xxx from file */
+    while (*s++ != '\0') {
+        if (found && i < 3)
+            suffix[i++] = *s;
+
+        if (*s == '.') {
+            if (found){
+                found = 0;
+                break;
+            }
+            found = 1;
+        }
+    }
+
+    /* check for all file definition of all groups for fitting suffix*/
+    for (i = 0; i < FILE_MAX && found; ++i) {
+        struct file *d = &media->files[i];
+        {
+            const char *f = d->suffix;
+            s = suffix;
+            while (f && *f && *s && *s == *f) {
+                s++; f++;
+            }
+
+            /* found correct file definition so */
+            if (f && *s == '\0' && *f == '\0')
+                return media->group[d->group].icon;
+        }
+    }
+    return &media->icons.default_file;
+}
+
+static void
+media_init(struct media *media)
+{
+    /* file groups */
+    struct icons *icons = &media->icons;
+    media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file);
+    media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file);
+    media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file);
+    media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file);
+    media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file);
+    media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file);
+
+    /* files */
+    media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);
+    media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT);
+    media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT);
+    media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT);
+    media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT);
+    media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT);
+    media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC);
+    media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC);
+    media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC);
+    media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT);
+    media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE);
+    media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE);
+    media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE);
+    media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE);
+    media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE);
+    media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE);
+}
+
+static void
+file_browser_reload_directory_content(struct file_browser *browser, const char *path)
+{
+    strncpy(browser->directory, path, MAX_PATH_LEN);
+    dir_free_list(browser->files, browser->file_count);
+    dir_free_list(browser->directories, browser->dir_count);
+    browser->files = dir_list(path, 0, &browser->file_count);
+    browser->directories = dir_list(path, 1, &browser->dir_count);
+}
+
+static void
+file_browser_init(struct file_browser *browser, struct media *media)
+{
+    memset(browser, 0, sizeof(*browser));
+    browser->media = media;
+    {
+        /* load files and sub-directory list */
+        const char *home = getenv("HOME");
+#ifdef _WIN32
+        if (!home) home = getenv("USERPROFILE");
+#else
+        if (!home) home = getpwuid(getuid())->pw_dir;
+        {
+            size_t l;
+            strncpy(browser->home, home, MAX_PATH_LEN);
+            l = strlen(browser->home);
+            strcpy(browser->home + l, "/");
+            strcpy(browser->directory, browser->home);
+        }
+#endif
+        {
+            size_t l;
+            strcpy(browser->desktop, browser->home);
+            l = strlen(browser->desktop);
+            strcpy(browser->desktop + l, "desktop/");
+        }
+        browser->files = dir_list(browser->directory, 0, &browser->file_count);
+        browser->directories = dir_list(browser->directory, 1, &browser->dir_count);
+    }
+}
+
+static void
+file_browser_free(struct file_browser *browser)
+{
+    if (browser->files)
+        dir_free_list(browser->files, browser->file_count);
+    if (browser->directories)
+        dir_free_list(browser->directories, browser->dir_count);
+    browser->files = NULL;
+    browser->directories = NULL;
+    memset(browser, 0, sizeof(*browser));
+}
+
+static int
+file_browser_run(struct file_browser *browser, struct nk_context *ctx)
+{
+    int ret = 0;
+    struct nk_panel layout;
+    struct media *media = browser->media;
+    struct nk_rect total_space;
+
+    if (nk_begin(ctx, &layout, "File Browser", nk_rect(50, 50, 800, 600),
+        NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_CLOSABLE|NK_WINDOW_MOVABLE))
+    {
+        struct nk_panel sub;
+        static float ratio[] = {0.25f, NK_UNDEFINED};
+        float spacing_x = ctx->style.window.spacing.x;
+
+        /* output path directory selector in the menubar */
+        ctx->style.window.spacing.x = 0;
+        nk_menubar_begin(ctx);
+        {
+            char *d = browser->directory;
+            char *begin = d + 1;
+            nk_layout_row_dynamic(ctx, 25, 6);
+            while (*d++) {
+                if (*d == '/') {
+                    *d = '\0';
+                    if (nk_button_label(ctx, begin, NK_BUTTON_DEFAULT)) {
+                        *d++ = '/'; *d = '\0';
+                        file_browser_reload_directory_content(browser, browser->directory);
+                        break;
+                    }
+                    *d = '/';
+                    begin = d + 1;
+                }
+            }
+        }
+        nk_menubar_end(ctx);
+        ctx->style.window.spacing.x = spacing_x;
+
+        /* window layout */
+        total_space = nk_window_get_content_region(ctx);
+        nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio);
+        nk_group_begin(ctx, &sub, "Special", NK_WINDOW_NO_SCROLLBAR);
+        {
+            struct nk_image home = media->icons.home;
+            struct nk_image desktop = media->icons.desktop;
+            struct nk_image computer = media->icons.computer;
+
+            nk_layout_row_dynamic(ctx, 40, 1);
+            if (nk_button_image_label(ctx, home, "home", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
+                file_browser_reload_directory_content(browser, browser->home);
+            if (nk_button_image_label(ctx,desktop,"desktop",NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
+                file_browser_reload_directory_content(browser, browser->desktop);
+            if (nk_button_image_label(ctx,computer,"computer",NK_TEXT_CENTERED,NK_BUTTON_DEFAULT))
+                file_browser_reload_directory_content(browser, "/");
+            nk_group_end(ctx);
+        }
+
+        /* output directory content window */
+        nk_group_begin(ctx, &sub, "Content", 0);
+        {
+            int index = -1;
+            size_t i = 0, j = 0, k = 0;
+            size_t rows = 0, cols = 0;
+            size_t count = browser->dir_count + browser->file_count;
+
+            cols = 4;
+            rows = count / cols;
+            for (i = 0; i <= rows; i += 1) {
+                {size_t n = j + cols;
+                nk_layout_row_dynamic(ctx, 135, (int)cols);
+                for (; j < count && j < n; ++j) {
+                    /* draw one row of icons */
+                    if (j < browser->dir_count) {
+                        /* draw and execute directory buttons */
+                        if (nk_button_image(ctx,media->icons.directory,NK_BUTTON_DEFAULT))
+                            index = (int)j;
+                    } else {
+                        /* draw and execute files buttons */
+                        struct nk_image *icon;
+                        size_t fileIndex = ((size_t)j - browser->dir_count);
+                        icon = media_icon_for_file(media,browser->files[fileIndex]);
+                        if (nk_button_image(ctx, *icon, NK_BUTTON_DEFAULT)) {
+                            strncpy(browser->file, browser->directory, MAX_PATH_LEN);
+                            n = strlen(browser->file);
+                            strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);
+                            ret = 1;
+                        }
+                    }
+                }}
+                {size_t n = k + cols;
+                nk_layout_row_dynamic(ctx, 20, (int)cols);
+                for (; k < count && k < n; k++) {
+                    /* draw one row of labels */
+                    if (k < browser->dir_count) {
+                        nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED);
+                    } else {
+                        size_t t = k-browser->dir_count;
+                        nk_label(ctx,browser->files[t],NK_TEXT_CENTERED);
+                    }
+                }}
+            }
+
+            if (index != -1) {
+                size_t n = strlen(browser->directory);
+                strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);
+                n = strlen(browser->directory);
+                if (n < MAX_PATH_LEN - 1) {
+                    browser->directory[n] = '/';
+                    browser->directory[n+1] = '\0';
+                }
+                file_browser_reload_directory_content(browser, browser->directory);
+                sub.offset->y = 0;
+            }
+            nk_group_end(ctx);
+        }
+    }
+    nk_end(ctx);
+    return ret;
+}
+
+/* ===============================================================
+ *
+ *                          DEVICE
+ *
+ * ===============================================================*/
+struct device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+static struct nk_image
+icon_load(const char *filename)
+{
+    int x,y,n;
+    GLuint tex;
+    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+    if (!data) die("[SDL]: failed to load image: %s", filename);
+
+    glGenTextures(1, &tex);
+    glBindTexture(GL_TEXTURE_2D, tex);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+    glGenerateMipmap(GL_TEXTURE_2D);
+    stbi_image_free(data);
+    return nk_image_id((int)tex);
+}
+
+static void
+device_init(struct device *dev)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+    enum nk_anti_aliasing AA)
+{
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+    /* Platform */
+    static GLFWwindow *win;
+    int width = 0, height = 0;
+
+    /* GUI */
+    struct device device;
+    struct nk_context ctx;
+    struct nk_font *font;
+    struct nk_font_atlas atlas;
+    struct file_browser browser;
+    struct media media;
+
+    /* GLFW */
+    glfwSetErrorCallback(error_callback);
+    if (!glfwInit()) {
+        fprintf(stdout, "[GFLW] failed to init!\n");
+        exit(1);
+    }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwMakeContextCurrent(win);
+    glfwSetWindowUserPointer(win, &ctx);
+    glfwSetCharCallback(win, text_input);
+    glfwSetScrollCallback(win, scroll_input);
+
+    /* OpenGL */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    {/* GUI */
+    device_init(&device);
+    {const void *image; int w, h;
+    const char *font_path = (argc > 1) ? argv[1]: 0;
+    nk_font_atlas_init_default(&atlas);
+    nk_font_atlas_begin(&atlas);
+    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
+    else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
+    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    device_upload_atlas(&device, image, w, h);
+    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+    nk_init_default(&ctx, &font->handle);}
+
+    /* icons */
+    glEnable(GL_TEXTURE_2D);
+    media.icons.home = icon_load("../icon/home.png");
+    media.icons.directory = icon_load("../icon/directory.png");
+    media.icons.computer = icon_load("../icon/computer.png");
+    media.icons.desktop = icon_load("../icon/desktop.png");
+    media.icons.default_file = icon_load("../icon/default.png");
+    media.icons.text_file = icon_load("../icon/text.png");
+    media.icons.music_file = icon_load("../icon/music.png");
+    media.icons.font_file =  icon_load("../icon/font.png");
+    media.icons.img_file = icon_load("../icon/img.png");
+    media.icons.movie_file = icon_load("../icon/movie.png");
+    media_init(&media);
+
+    file_browser_init(&browser, &media);
+    while (!glfwWindowShouldClose(win))
+    {
+        /* Input */
+        {double x, y;
+        nk_input_begin(&ctx);
+        glfwPollEvents();
+        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
+            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+        } else {
+            nk_input_key(&ctx, NK_KEY_COPY, 0);
+            nk_input_key(&ctx, NK_KEY_PASTE, 0);
+            nk_input_key(&ctx, NK_KEY_CUT, 0);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+        }
+        glfwGetCursorPos(win, &x, &y);
+        nk_input_motion(&ctx, (int)x, (int)y);
+        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+        nk_input_end(&ctx);}
+
+        /* GUI */
+        file_browser_run(&browser, &ctx);
+
+        /* Draw */
+        glfwGetWindowSize(win, &width, &height);
+        glViewport(0, 0, width, height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+        device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
+        glfwSwapBuffers(win);
+    }
+
+    glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id);
+    glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id);
+
+    file_browser_free(&browser);
+    nk_font_atlas_clear(&atlas);
+    nk_free(&ctx);
+    device_shutdown(&device);
+    glfwTerminate();
+    return 0;
+}
+
+

+ 0 - 0
demo/icon/checked.png → example/icon/checked.png


+ 0 - 0
demo/icon/cloud.png → example/icon/cloud.png


+ 0 - 0
demo/icon/computer.png → example/icon/computer.png


+ 0 - 0
demo/icon/copy.png → example/icon/copy.png


+ 0 - 0
demo/icon/default.png → example/icon/default.png


+ 0 - 0
demo/icon/delete.png → example/icon/delete.png


+ 0 - 0
demo/icon/desktop.png → example/icon/desktop.png


+ 0 - 0
demo/icon/directory.png → example/icon/directory.png


+ 0 - 0
demo/icon/edit.png → example/icon/edit.png


+ 0 - 0
demo/icon/export.png → example/icon/export.png


+ 0 - 0
demo/icon/font.png → example/icon/font.png


+ 0 - 0
demo/icon/home.png → example/icon/home.png


+ 0 - 0
demo/icon/img.png → example/icon/img.png


+ 0 - 0
demo/icon/movie.png → example/icon/movie.png


+ 0 - 0
demo/icon/music.png → example/icon/music.png


+ 0 - 0
demo/icon/next.png → example/icon/next.png


+ 0 - 0
demo/icon/pause.png → example/icon/pause.png


+ 0 - 0
demo/icon/pen.png → example/icon/pen.png


+ 0 - 0
demo/icon/phone.png → example/icon/phone.png


+ 0 - 0
demo/icon/plane.png → example/icon/plane.png


+ 0 - 0
demo/icon/play.png → example/icon/play.png


+ 0 - 0
demo/icon/prev.png → example/icon/prev.png


+ 0 - 0
demo/icon/rocket.png → example/icon/rocket.png


+ 0 - 0
demo/icon/settings.png → example/icon/settings.png


+ 0 - 0
demo/icon/stop.png → example/icon/stop.png


+ 0 - 0
demo/icon/text.png → example/icon/text.png


+ 0 - 0
demo/icon/tools.png → example/icon/tools.png


+ 0 - 0
demo/icon/unchecked.png → example/icon/unchecked.png


+ 0 - 0
demo/icon/volume.png → example/icon/volume.png


+ 0 - 0
demo/icon/wifi.png → example/icon/wifi.png


+ 0 - 0
demo/images/image1.png → example/images/image1.png


+ 0 - 0
demo/images/image2.png → example/images/image2.png


+ 0 - 0
demo/images/image3.png → example/images/image3.png


+ 0 - 0
demo/images/image4.png → example/images/image4.png


+ 0 - 0
demo/images/image5.png → example/images/image5.png


+ 0 - 0
demo/images/image6.png → example/images/image6.png


+ 0 - 0
demo/images/image7.png → example/images/image7.png


+ 0 - 0
demo/images/image8.png → example/images/image8.png


+ 0 - 0
demo/images/image9.png → example/images/image9.png


+ 715 - 0
example/node_editor.c

@@ -0,0 +1,715 @@
+/* nuklear - v1.00 - public domain */
+/* This is a simple node editor just to show a simple implementation and that
+ * it is possible to achieve it with this library. While all nodes inside this
+ * example use a simple color modifier as content you could change them
+ * to have your custom content depending on the node time.
+ * Biggest difference to most usual implementation is that this example does
+ * not has connectors on the right position of the property that it links.
+ * This is mainly done out of lazyness and could be implemented as well but
+ * requires calculating the position of all rows and add connectors.
+ * In addition adding and removing nodes is quite limited at the
+ * moment since it is based on a simple fixed array. If this is to be converted
+ * into something more serious it is probably best to extend it.*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+/* macros */
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          NODE EDITOR
+ *
+ * ===============================================================*/
+struct node {
+    int ID;
+    char name[32];
+    struct nk_rect bounds;
+    float value;
+    struct nk_color color;
+    int input_count;
+    int output_count;
+    struct node *next;
+    struct node *prev;
+};
+
+struct node_link {
+    int input_id;
+    int input_slot;
+    int output_id;
+    int output_slot;
+    struct nk_vec2 in;
+    struct nk_vec2 out;
+};
+
+struct node_linking {
+    int active;
+    struct node *node;
+    int input_id;
+    int input_slot;
+};
+
+struct node_editor {
+    struct node node_buf[32];
+    struct node_link links[64];
+    struct node *begin;
+    struct node *end;
+    int node_count;
+    int link_count;
+    struct nk_rect bounds;
+    struct node *selected;
+    int show_grid;
+    struct nk_vec2 scrolling;
+    struct node_linking linking;
+};
+
+static void
+node_editor_push(struct node_editor *editor, struct node *node)
+{
+    if (!editor->begin) {
+        node->next = NULL;
+        node->prev = NULL;
+        editor->begin = node;
+        editor->end = node;
+    } else {
+        node->prev = editor->end;
+        if (editor->end)
+            editor->end->next = node;
+        node->next = NULL;
+        editor->end = node;
+    }
+}
+
+static void
+node_editor_pop(struct node_editor *editor, struct node *node)
+{
+    if (node->next)
+        node->next->prev = node->prev;
+    if (node->prev)
+        node->prev->next = node->next;
+    if (editor->end == node)
+        editor->end = node->prev;
+    if (editor->begin == node)
+        editor->begin = node->next;
+    node->next = NULL;
+    node->prev = NULL;
+}
+
+static struct node*
+node_editor_find(struct node_editor *editor, int ID)
+{
+    struct node *iter = editor->begin;
+    while (iter) {
+        if (iter->ID == ID)
+            return iter;
+        iter = iter->next;
+    }
+    return NULL;
+}
+
+static void
+node_editor_add(struct node_editor *editor, const char *name, struct nk_rect bounds,
+    struct nk_color col, int in_count, int out_count)
+{
+    static int IDs = 0;
+    struct node *node;
+    assert((nk_size)editor->node_count < LEN(editor->node_buf));
+    node = &editor->node_buf[editor->node_count++];
+    node->ID = IDs++;
+    node->value = 0;
+    node->color = nk_rgb(255, 0, 0);
+    node->input_count = in_count;
+    node->output_count = out_count;
+    node->color = col;
+    node->bounds = bounds;
+    strcpy(node->name, name);
+    node_editor_push(editor, node);
+}
+
+static void
+node_editor_link(struct node_editor *editor, int in_id, int in_slot,
+    int out_id, int out_slot)
+{
+    struct node_link *link;
+    assert((nk_size)editor->link_count < LEN(editor->links));
+    link = &editor->links[editor->link_count++];
+    link->input_id = in_id;
+    link->input_slot = in_slot;
+    link->output_id = out_id;
+    link->output_slot = out_slot;
+}
+
+static void
+node_editor_init(struct node_editor *editor)
+{
+    memset(editor, 0, sizeof(*editor));
+    editor->begin = NULL;
+    editor->end = NULL;
+    node_editor_add(editor, "Source", nk_rect(-40, 10, 180, 220), nk_rgb(255, 0, 0), 0, 1);
+    node_editor_add(editor, "Source", nk_rect(-40, 260, 180, 220), nk_rgb(0, 255, 0), 0, 1);
+    node_editor_add(editor, "Combine", nk_rect(400, 100, 180, 220), nk_rgb(0,0,255), 2, 2);
+    node_editor_link(editor, 0, 0, 2, 0);
+    node_editor_link(editor, 1, 0, 2, 1);
+    editor->show_grid = nk_true;
+}
+
+static int
+node_editor_run(struct node_editor *nodedit, struct nk_context *ctx)
+{
+    int n = 0;
+    struct nk_rect total_space;
+    const struct nk_input *in = &ctx->input;
+    struct nk_command_buffer *canvas;
+    struct node *updated = 0;
+    struct nk_panel layout;
+
+    if (nk_begin(ctx, &layout, "Node Editor", nk_rect(50, 50, WINDOW_WIDTH, WINDOW_HEIGHT),
+        NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
+    {
+        /* allocate complete window space */
+        canvas = nk_window_get_canvas(ctx);
+        total_space = nk_window_get_content_region(ctx);
+        nk_layout_space_begin(ctx, NK_STATIC, total_space.h, nodedit->node_count);
+        {
+            struct nk_panel node, menu;
+            struct node *it = nodedit->begin;
+            struct nk_rect size = nk_layout_space_bounds(ctx);
+
+            if (nodedit->show_grid) {
+                /* display grid */
+                float x, y;
+                const float grid_size = 32.0f;
+                const struct nk_color grid_color = nk_rgb(50, 50, 50);
+                for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size)
+                    nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color);
+                for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size)
+                    nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color);
+            }
+
+            /* execute each node as a moveable group */
+            while (it) {
+                /* calculate scrolled node window position and size */
+                nk_layout_space_push(ctx, nk_rect(it->bounds.x - nodedit->scrolling.x,
+                    it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h));
+
+                /* execute node window */
+                if (nk_group_begin(ctx, &node, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE))
+                {
+                    /* always have last selected node on top */
+                    if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, node.bounds) &&
+                        (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
+                        nk_layout_space_rect_to_screen(ctx, node.bounds)))) &&
+                        nodedit->end != it)
+                    {
+                        updated = it;
+                    }
+
+                    /* ================= NODE CONTENT =====================*/
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    nk_button_color(ctx, it->color, NK_BUTTON_DEFAULT);
+                    it->color.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1);
+                    it->color.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1);
+                    it->color.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1);
+                    it->color.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1);
+                    /* ====================================================*/
+                    nk_group_end(ctx);
+                }
+                {
+                    /* node connector and linking */
+                    float space;
+                    struct nk_rect bounds;
+                    bounds = nk_layout_space_rect_to_local(ctx, node.bounds);
+                    bounds.x += nodedit->scrolling.x - ctx->style.window.border;
+                    bounds.y += nodedit->scrolling.y - ctx->style.window.border;
+                    bounds.w += 2*ctx->style.window.border;
+                    bounds.h += 2*ctx->style.window.border;
+
+                    it->bounds = bounds;
+
+                    /* output connector */
+                    space = node.bounds.h / (float)((it->output_count) + 1);
+                    for (n = 0; n < it->output_count; ++n) {
+                        struct nk_rect circle;
+                        circle.x = node.bounds.x + node.bounds.w-4;
+                        circle.y = node.bounds.y + space * (float)(n+1);
+                        circle.w = 8; circle.h = 8;
+                        nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
+
+                        /* start linking process */
+                        if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
+                            nodedit->linking.active = nk_true;
+                            nodedit->linking.node = it;
+                            nodedit->linking.input_id = it->ID;
+                            nodedit->linking.input_slot = n;
+                        }
+
+                        /* draw curve from linked node slot to mouse position */
+                        if (nodedit->linking.active && nodedit->linking.node == it &&
+                            nodedit->linking.input_slot == n) {
+                            struct nk_vec2 l0 = nk_vec2(circle.x + 3, circle.y + 3);
+                            struct nk_vec2 l1 = in->mouse.pos;
+                            nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
+                                l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
+                        }
+                    }
+
+                    /* input connector */
+                    space = node.bounds.h / (float)((it->input_count) + 1);
+                    for (n = 0; n < it->input_count; ++n) {
+                        struct nk_rect circle;
+                        circle.x = node.bounds.x-4;
+                        circle.y = node.bounds.y + space * (float)(n+1);
+                        circle.w = 8; circle.h = 8;
+                        nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
+                        if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
+                            nk_input_is_mouse_hovering_rect(in, circle) &&
+                            nodedit->linking.active && nodedit->linking.node != it) {
+                            nodedit->linking.active = nk_false;
+                            node_editor_link(nodedit, nodedit->linking.input_id,
+                                nodedit->linking.input_slot, it->ID, n);
+                        }
+                    }
+                }
+                it = it->next;
+            }
+
+            /* reset linking connection */
+            if (nodedit->linking.active && nk_input_is_mouse_released(in, NK_BUTTON_LEFT)) {
+                nodedit->linking.active = nk_false;
+                nodedit->linking.node = NULL;
+                fprintf(stdout, "linking failed\n");
+            }
+
+            /* draw each link */
+            for (n = 0; n < nodedit->link_count; ++n) {
+                struct node_link *link = &nodedit->links[n];
+                struct node *ni = node_editor_find(nodedit, link->input_id);
+                struct node *no = node_editor_find(nodedit, link->output_id);
+                float spacei = node.bounds.h / (float)((ni->output_count) + 1);
+                float spaceo = node.bounds.h / (float)((no->input_count) + 1);
+                struct nk_vec2 l0 = nk_layout_space_to_screen(ctx,
+                    nk_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1)));
+                struct nk_vec2 l1 = nk_layout_space_to_screen(ctx,
+                    nk_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1)));
+
+                l0.x -= nodedit->scrolling.x;
+                l0.y -= nodedit->scrolling.y;
+                l1.x -= nodedit->scrolling.x;
+                l1.y -= nodedit->scrolling.y;
+                nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
+                    l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
+            }
+
+            if (updated) {
+                /* reshuffle nodes to have least recently selected node on top */
+                node_editor_pop(nodedit, updated);
+                node_editor_push(nodedit, updated);
+            }
+
+            /* node selection */
+            if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ctx))) {
+                it = nodedit->begin;
+                nodedit->selected = NULL;
+                nodedit->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
+                while (it) {
+                    struct nk_rect b = nk_layout_space_rect_to_screen(ctx, it->bounds);
+                    b.x -= nodedit->scrolling.x;
+                    b.y -= nodedit->scrolling.y;
+                    if (nk_input_is_mouse_hovering_rect(in, b))
+                        nodedit->selected = it;
+                    it = it->next;
+                }
+            }
+
+            /* contextual menu */
+            if (nk_contextual_begin(ctx, &menu, 0, nk_vec2(100, 220), nk_window_get_bounds(ctx))) {
+                const char *grid_option[] = {"Show Grid", "Hide Grid"};
+                nk_layout_row_dynamic(ctx, 25, 1);
+                if (nk_contextual_item_label(ctx, "New", NK_TEXT_CENTERED))
+                    node_editor_add(nodedit, "New", nk_rect(400, 260, 180, 220),
+                            nk_rgb(255, 255, 255), 1, 2);
+                if (nk_contextual_item_label(ctx, grid_option[nodedit->show_grid],NK_TEXT_CENTERED))
+                    nodedit->show_grid = !nodedit->show_grid;
+                nk_contextual_end(ctx);
+            }
+        }
+        nk_layout_space_end(ctx);
+
+        /* window content scrolling */
+        if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ctx)) &&
+            nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
+            nodedit->scrolling.x += in->mouse.delta.x;
+            nodedit->scrolling.y += in->mouse.delta.y;
+        }
+    }
+    nk_end(ctx);
+    return !nk_window_is_closed(ctx, "Node Editor");
+}
+
+/* ===============================================================
+ *
+ *                          DEVICE
+ *
+ * ===============================================================*/
+struct device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+static void
+device_init(struct device *dev)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+    enum nk_anti_aliasing AA)
+{
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+    /* Platform */
+    static GLFWwindow *win;
+    int width = 0, height = 0;
+
+    /* GUI */
+    struct device device;
+    struct nk_context ctx;
+    struct nk_font *font;
+    struct nk_font_atlas atlas;
+    struct node_editor node;
+
+    /* GLFW */
+    glfwSetErrorCallback(error_callback);
+    if (!glfwInit()) {
+        fprintf(stdout, "[GFLW] failed to init!\n");
+        exit(1);
+    }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwMakeContextCurrent(win);
+    glfwSetWindowUserPointer(win, &ctx);
+    glfwSetCharCallback(win, text_input);
+    glfwSetScrollCallback(win, scroll_input);
+
+    /* OpenGL */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    {/* GUI */
+    device_init(&device);
+    {const void *image; int w, h;
+    const char *font_path = (argc > 1) ? argv[1]: 0;
+    nk_font_atlas_init_default(&atlas);
+    nk_font_atlas_begin(&atlas);
+    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
+    else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
+    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    device_upload_atlas(&device, image, w, h);
+    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+    nk_init_default(&ctx, &font->handle);}
+
+    node_editor_init(&node);
+    while (!glfwWindowShouldClose(win))
+    {
+        /* Input */
+        {double x, y;
+        nk_input_begin(&ctx);
+        glfwPollEvents();
+        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
+            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+        } else {
+            nk_input_key(&ctx, NK_KEY_COPY, 0);
+            nk_input_key(&ctx, NK_KEY_PASTE, 0);
+            nk_input_key(&ctx, NK_KEY_CUT, 0);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+        }
+        glfwGetCursorPos(win, &x, &y);
+        nk_input_motion(&ctx, (int)x, (int)y);
+        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+        nk_input_end(&ctx);}
+
+        /* GUI */
+        if (!node_editor_run(&node, &ctx)) break;
+
+        /* Draw */
+        glfwGetWindowSize(win, &width, &height);
+        glViewport(0, 0, width, height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+        device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
+        glfwSwapBuffers(win);
+    }
+
+    nk_font_atlas_clear(&atlas);
+    nk_free(&ctx);
+    device_shutdown(&device);
+    glfwTerminate();
+    return 0;
+}
+

+ 1466 - 0
example/overview.c

@@ -0,0 +1,1466 @@
+/* nuklear - v1.00 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+/* macros */
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          GUI
+ *
+ * ===============================================================*/
+static int
+overview_window(struct nk_context *ctx)
+{
+    struct nk_panel menu;
+
+    /* window flags */
+    static int show_menu = nk_true;
+    static int titlebar = nk_true;
+    static int border = nk_true;
+    static int resize = nk_true;
+    static int moveable = nk_true;
+    static int no_scrollbar = nk_false;
+    static nk_flags window_flags = 0;
+    static int minimizable = nk_true;
+    static int close = nk_true;
+
+    /* popups */
+    static enum nk_style_header_align header_align = NK_HEADER_RIGHT;
+    static int show_app_about = nk_false;
+    struct nk_panel layout;
+
+    /* window flags */
+    window_flags = 0;
+    ctx->style.window.header.align = header_align;
+    if (border) window_flags |= NK_WINDOW_BORDER;
+    if (resize) window_flags |= NK_WINDOW_SCALABLE;
+    if (moveable) window_flags |= NK_WINDOW_MOVABLE;
+    if (no_scrollbar) window_flags |= NK_WINDOW_NO_SCROLLBAR;
+    if (minimizable) window_flags |= NK_WINDOW_MINIMIZABLE;
+    if (close) window_flags |= NK_WINDOW_CLOSABLE;
+
+    if (nk_begin(ctx, &layout, "Demo", nk_rect(10, 10, 400, 750), window_flags))
+    {
+        if (show_menu)
+        {
+            /* menubar */
+            enum menu_states {MENU_DEFAULT, MENU_WINDOWS};
+            static enum menu_states menu_state = MENU_DEFAULT;
+            static nk_size mprog = 60;
+            static int mslider = 10;
+            static int mcheck = nk_true;
+
+            nk_menubar_begin(ctx);
+            nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
+            nk_layout_row_push(ctx, 45);
+            if (nk_menu_begin_label(ctx, &menu, "MENU", NK_TEXT_LEFT, 120))
+            {
+                static size_t prog = 40;
+                static int slider = 10;
+                static int check = nk_true;
+                nk_layout_row_dynamic(ctx, 25, 1);
+                if (nk_menu_item_label(ctx, "Hide", NK_TEXT_LEFT))
+                    show_menu = nk_false;
+                if (nk_menu_item_label(ctx, "About", NK_TEXT_LEFT))
+                    show_app_about = nk_true;
+                nk_progress(ctx, &prog, 100, NK_MODIFIABLE);
+                nk_slider_int(ctx, 0, &slider, 16, 1);
+                nk_checkbox_label(ctx, "check", &check);
+                nk_menu_end(ctx);
+            }
+            nk_layout_row_push(ctx, 70);
+            nk_progress(ctx, &mprog, 100, NK_MODIFIABLE);
+            nk_slider_int(ctx, 0, &mslider, 16, 1);
+            nk_checkbox_label(ctx, "check", &mcheck);
+            nk_menubar_end(ctx);
+        }
+
+        if (show_app_about)
+        {
+            /* about popup */
+            struct nk_panel popup;
+            static struct nk_rect s = {20, 100, 300, 190};
+            if (nk_popup_begin(ctx, &popup, NK_POPUP_STATIC, "About", NK_WINDOW_CLOSABLE, s))
+            {
+                nk_layout_row_dynamic(ctx, 20, 1);
+                nk_label(ctx, "nuklear", NK_TEXT_LEFT);
+                nk_label(ctx, "By Micha Mettke", NK_TEXT_LEFT);
+                nk_label(ctx, "nuklear is licensed under the zlib License.",  NK_TEXT_LEFT);
+                nk_label(ctx, "See LICENSE for more information", NK_TEXT_LEFT);
+                nk_popup_end(ctx);
+            } else show_app_about = nk_false;
+        }
+
+        /* window flags */
+        if (nk_tree_push(ctx, NK_TREE_TAB, "Window", NK_MINIMIZED)) {
+            nk_layout_row_dynamic(ctx, 30, 2);
+            nk_checkbox_label(ctx, "Titlebar", &titlebar);
+            nk_checkbox_label(ctx, "Menu", &show_menu);
+            nk_checkbox_label(ctx, "Border", &border);
+            nk_checkbox_label(ctx, "Resizable", &resize);
+            nk_checkbox_label(ctx, "Moveable", &moveable);
+            nk_checkbox_label(ctx, "No Scrollbar", &no_scrollbar);
+            nk_checkbox_label(ctx, "Minimizable", &minimizable);
+            nk_checkbox_label(ctx, "Closeable", &close);
+            nk_tree_pop(ctx);
+        }
+
+        if (nk_tree_push(ctx, NK_TREE_TAB, "Widgets", NK_MINIMIZED))
+        {
+            enum options {A,B,C};
+            static int checkbox;
+            static int option;
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Text", NK_MINIMIZED))
+            {
+                /* Text Widgets */
+                nk_layout_row_dynamic(ctx, 20, 1);
+                nk_label(ctx, "Label aligned left", NK_TEXT_LEFT);
+                nk_label(ctx, "Label aligned centered", NK_TEXT_CENTERED);
+                nk_label(ctx, "Label aligned right", NK_TEXT_RIGHT);
+                nk_label_colored(ctx, "Blue text", NK_TEXT_LEFT, nk_rgb(0,0,255));
+                nk_label_colored(ctx, "Yellow text", NK_TEXT_LEFT, nk_rgb(255,255,0));
+                nk_text(ctx, "Text without /0", 15, NK_TEXT_RIGHT);
+
+                nk_layout_row_static(ctx, 100, 200, 1);
+                nk_label_wrap(ctx, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping");
+                nk_layout_row_dynamic(ctx, 100, 1);
+                nk_label_wrap(ctx, "This is another long text to show dynamic window changes on multiline text");
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Button", NK_MINIMIZED))
+            {
+                /* Buttons Widgets */
+                nk_layout_row_static(ctx, 30, 100, 3);
+                if (nk_button_label(ctx, "Button", NK_BUTTON_DEFAULT))
+                    fprintf(stdout, "Button pressed!\n");
+                if (nk_button_label(ctx, "Repeater", NK_BUTTON_REPEATER))
+                    fprintf(stdout, "Repeater is being pressed!\n");
+                nk_button_color(ctx, nk_rgb(0,0,255), NK_BUTTON_DEFAULT);
+
+                nk_layout_row_static(ctx, 20, 20, 8);
+                nk_button_symbol(ctx, NK_SYMBOL_CIRCLE, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_FILLED, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_RECT, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_RECT_FILLED, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT, NK_BUTTON_DEFAULT);
+                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT, NK_BUTTON_DEFAULT);
+
+                nk_layout_row_static(ctx, 30, 100, 2);
+                nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_LEFT, "prev", NK_TEXT_RIGHT, NK_BUTTON_DEFAULT);
+                nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_RIGHT, "next", NK_TEXT_LEFT, NK_BUTTON_DEFAULT);
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Basic", NK_MINIMIZED))
+            {
+                /* Basic widgets */
+                static int int_slider = 5;
+                static float float_slider = 2.5f;
+                static size_t prog_value = 40;
+                static float property_float = 2;
+                static int property_int = 10;
+                static int property_neg = 10;
+
+                static float range_float_min = 0;
+                static float range_float_max = 100;
+                static float range_float_value = 50;
+                static int range_int_min = 0;
+                static int range_int_value = 2048;
+                static int range_int_max = 4096;
+                static const float ratio[] = {120, 150};
+
+                nk_layout_row_static(ctx, 30, 100, 1);
+                nk_checkbox_label(ctx, "Checkbox", &checkbox);
+
+                nk_layout_row_static(ctx, 30, 80, 3);
+                option = nk_option_label(ctx, "optionA", option == A) ? A : option;
+                option = nk_option_label(ctx, "optionB", option == B) ? B : option;
+                option = nk_option_label(ctx, "optionC", option == C) ? C : option;
+
+
+                nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);
+                nk_labelf(ctx, NK_TEXT_LEFT, "Slider int");
+                nk_slider_int(ctx, 0, &int_slider, 10, 1);
+
+                nk_label(ctx, "Slider float", NK_TEXT_LEFT);
+                nk_slider_float(ctx, 0, &float_slider, 5.0, 0.5f);
+                nk_labelf(ctx, NK_TEXT_LEFT, "Progressbar" , prog_value);
+                nk_progress(ctx, &prog_value, 100, NK_MODIFIABLE);
+
+                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+                nk_label(ctx, "Property float:", NK_TEXT_LEFT);
+                nk_property_float(ctx, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f);
+                nk_label(ctx, "Property int:", NK_TEXT_LEFT);
+                nk_property_int(ctx, "Int:", 0, &property_int, 100.0f, 1, 1);
+                nk_label(ctx, "Property neg:", NK_TEXT_LEFT);
+                nk_property_int(ctx, "Neg:", -10, &property_neg, 10, 1, 1);
+
+                nk_layout_row_dynamic(ctx, 25, 1);
+                nk_label(ctx, "Range:", NK_TEXT_LEFT);
+                nk_layout_row_dynamic(ctx, 25, 3);
+                nk_property_float(ctx, "#min:", 0, &range_float_min, range_float_max, 1.0f, 0.2f);
+                nk_property_float(ctx, "#float:", range_float_min, &range_float_value, range_float_max, 1.0f, 0.2f);
+                nk_property_float(ctx, "#max:", range_float_min, &range_float_max, 100, 1.0f, 0.2f);
+
+                nk_property_int(ctx, "#min:", INT_MIN, &range_int_min, range_int_max, 1, 10);
+                nk_property_int(ctx, "#neg:", range_int_min, &range_int_value, range_int_max, 1, 10);
+                nk_property_int(ctx, "#max:", range_int_min, &range_int_max, INT_MAX, 1, 10);
+
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Selectable", NK_MINIMIZED))
+            {
+                if (nk_tree_push(ctx, NK_TREE_NODE, "List", NK_MINIMIZED))
+                {
+                    static int selected[4] = {nk_false, nk_false, nk_true, nk_false};
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[0]);
+                    nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[1]);
+                    nk_label(ctx, "Not Selectable", NK_TEXT_LEFT);
+                    nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[2]);
+                    nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[3]);
+                    nk_tree_pop(ctx);
+                }
+                if (nk_tree_push(ctx, NK_TREE_NODE, "Grid", NK_MINIMIZED))
+                {
+                    int i;
+                    static int selected[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
+                    nk_layout_row_static(ctx, 50, 50, 4);
+                    for (i = 0; i < 16; ++i) {
+                        if (nk_selectable_label(ctx, "Z", NK_TEXT_CENTERED, &selected[i])) {
+                            int x = (i % 4), y = i / 4;
+                            if (x > 0) selected[i - 1] ^= 1;
+                            if (x < 3) selected[i + 1] ^= 1;
+                            if (y > 0) selected[i - 4] ^= 1;
+                            if (y < 3) selected[i + 4] ^= 1;
+                        }
+                    }
+                    nk_tree_pop(ctx);
+                }
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Combo", NK_MINIMIZED))
+            {
+                /* Combobox Widgets
+                 * In this library comboboxes are not limited to being a popup
+                 * list of selectable text. Instead it is a abstract concept of
+                 * having something that is *selected* or displayed, a popup window
+                 * which opens if something needs to be modified and the content
+                 * of the popup which causes the *selected* or displayed value to
+                 * change or if wanted close the combobox.
+                 *
+                 * While strange at first handling comboboxes in a abstract way
+                 * solves the problem of overloaded window content. For example
+                 * changing a color value requires 4 value modifier (slider, property,...)
+                 * for RGBA then you need a label and ways to display the current color.
+                 * If you want to go fancy you even add rgb and hsv ratio boxes.
+                 * While fine for one color if you have a lot of them it because
+                 * tedious to look at and quite wasteful in space. You could add
+                 * a popup which modifies the color but this does not solve the
+                 * fact that it still requires a lot of cluttered space to do.
+                 *
+                 * In these kind of instance abstract comboboxes are quite handy. All
+                 * value modifiers are hidden inside the combobox popup and only
+                 * the color is shown if not open. This combines the clarity of the
+                 * popup with the ease of use of just using the space for modifiers.
+                 *
+                 * Other instances are for example time and especially date picker,
+                 * which only show the currently activated time/data and hide the
+                 * selection logic inside the combobox popup.
+                 */
+                static float chart_selection = 8.0f;
+                static int current_weapon = 0;
+                static int check_values[5];
+                static float position[3];
+                static struct nk_color combo_color = {130, 50, 50, 255};
+                static struct nk_color combo_color2 = {130, 180, 50, 255};
+                static size_t prog_a =  20, prog_b = 40, prog_c = 10, prog_d = 90;
+                static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"};
+
+                char buffer[64];
+                size_t sum = 0;
+                struct nk_panel combo;
+
+                /* default combobox */
+                nk_layout_row_static(ctx, 25, 200, 1);
+                current_weapon = nk_combo(ctx, weapons, LEN(weapons), current_weapon, 25);
+
+                /* slider color combobox */
+                if (nk_combo_begin_color(ctx, &combo, combo_color, 200)) {
+                    float ratios[] = {0.15f, 0.85f};
+                    nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratios);
+                    nk_label(ctx, "R:", NK_TEXT_LEFT);
+                    combo_color.r = (nk_byte)nk_slide_int(ctx, 0, combo_color.r, 255, 5);
+                    nk_label(ctx, "G:", NK_TEXT_LEFT);
+                    combo_color.g = (nk_byte)nk_slide_int(ctx, 0, combo_color.g, 255, 5);
+                    nk_label(ctx, "B:", NK_TEXT_LEFT);
+                    combo_color.b = (nk_byte)nk_slide_int(ctx, 0, combo_color.b, 255, 5);
+                    nk_label(ctx, "A:", NK_TEXT_LEFT);
+                    combo_color.a = (nk_byte)nk_slide_int(ctx, 0, combo_color.a , 255, 5);
+                    nk_combo_end(ctx);
+                }
+
+                /* complex color combobox */
+                if (nk_combo_begin_color(ctx, &combo, combo_color2, 400)) {
+                    enum color_mode {COL_RGB, COL_HSV};
+                    static int col_mode = COL_RGB;
+                    #ifndef DEMO_DO_NOT_USE_COLOR_PICKER
+                    nk_layout_row_dynamic(ctx, 120, 1);
+                    combo_color2 = nk_color_picker(ctx, combo_color2, NK_RGBA);
+                    #endif
+
+                    nk_layout_row_dynamic(ctx, 25, 2);
+                    col_mode = nk_option_label(ctx, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode;
+                    col_mode = nk_option_label(ctx, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode;
+
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    if (col_mode == COL_RGB) {
+                        combo_color2.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, combo_color2.r, 255, 1,1);
+                        combo_color2.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, combo_color2.g, 255, 1,1);
+                        combo_color2.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, combo_color2.b, 255, 1,1);
+                        combo_color2.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, combo_color2.a, 255, 1,1);
+                    } else {
+                        nk_byte tmp[4];
+                        nk_color_hsva_bv(tmp, combo_color2);
+                        tmp[0] = (nk_byte)nk_propertyi(ctx, "#H:", 0, tmp[0], 255, 1,1);
+                        tmp[1] = (nk_byte)nk_propertyi(ctx, "#S:", 0, tmp[1], 255, 1,1);
+                        tmp[2] = (nk_byte)nk_propertyi(ctx, "#V:", 0, tmp[2], 255, 1,1);
+                        tmp[3] = (nk_byte)nk_propertyi(ctx, "#A:", 0, tmp[3], 255, 1,1);
+                        combo_color2 = nk_hsva_bv(tmp);
+                    }
+                    nk_combo_end(ctx);
+                }
+
+                /* progressbar combobox */
+                sum = prog_a + prog_b + prog_c + prog_d;
+                sprintf(buffer, "%lu", sum);
+                if (nk_combo_begin_label(ctx, &combo, buffer, 200)) {
+                    nk_layout_row_dynamic(ctx, 30, 1);
+                    nk_progress(ctx, &prog_a, 100, NK_MODIFIABLE);
+                    nk_progress(ctx, &prog_b, 100, NK_MODIFIABLE);
+                    nk_progress(ctx, &prog_c, 100, NK_MODIFIABLE);
+                    nk_progress(ctx, &prog_d, 100, NK_MODIFIABLE);
+                    nk_combo_end(ctx);
+                }
+
+                /* checkbox combobox */
+                sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]);
+                sprintf(buffer, "%lu", sum);
+                if (nk_combo_begin_label(ctx, &combo, buffer, 200)) {
+                    nk_layout_row_dynamic(ctx, 30, 1);
+                    nk_checkbox_label(ctx, weapons[0], &check_values[0]);
+                    nk_checkbox_label(ctx, weapons[1], &check_values[1]);
+                    nk_checkbox_label(ctx, weapons[2], &check_values[2]);
+                    nk_checkbox_label(ctx, weapons[3], &check_values[3]);
+                    nk_combo_end(ctx);
+                }
+
+                /* complex text combobox */
+                sprintf(buffer, "%.2f, %.2f, %.2f", position[0], position[1],position[2]);
+                if (nk_combo_begin_label(ctx, &combo, buffer, 200)) {
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    nk_property_float(ctx, "#X:", -1024.0f, &position[0], 1024.0f, 1,0.5f);
+                    nk_property_float(ctx, "#Y:", -1024.0f, &position[1], 1024.0f, 1,0.5f);
+                    nk_property_float(ctx, "#Z:", -1024.0f, &position[2], 1024.0f, 1,0.5f);
+                    nk_combo_end(ctx);
+                }
+
+                /* chart combobox */
+                sprintf(buffer, "%.1f", chart_selection);
+                if (nk_combo_begin_label(ctx, &combo, buffer, 250)) {
+                    size_t i = 0;
+                    static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f};
+                    nk_layout_row_dynamic(ctx, 150, 1);
+                    nk_chart_begin(ctx, NK_CHART_COLUMN, LEN(values), 0, 50);
+                    for (i = 0; i < LEN(values); ++i) {
+                        nk_flags res = nk_chart_push(ctx, values[i]);
+                        if (res & NK_CHART_CLICKED) {
+                            chart_selection = values[i];
+                            nk_combo_close(ctx);
+                        }
+                    }
+                    nk_chart_end(ctx);
+                    nk_combo_end(ctx);
+                }
+
+                {
+                    static int time_selected = 0;
+                    static int date_selected = 0;
+                    static struct tm sel_time;
+                    static struct tm sel_date;
+                    if (!time_selected || !date_selected) {
+                        /* keep time and date updated if nothing is selected */
+                        time_t cur_time = time(0);
+                        struct tm *n = localtime(&cur_time);
+                        if (!time_selected)
+                            memcpy(&sel_time, n, sizeof(struct tm));
+                        if (!date_selected)
+                            memcpy(&sel_date, n, sizeof(struct tm));
+                    }
+
+                    /* time combobox */
+                    sprintf(buffer, "%02d:%02d:%02d", sel_time.tm_hour, sel_time.tm_min, sel_time.tm_sec);
+                    if (nk_combo_begin_label(ctx, &combo, buffer, 250)) {
+                        time_selected = 1;
+                        nk_layout_row_dynamic(ctx, 25, 1);
+                        sel_time.tm_sec = nk_propertyi(ctx, "#S:", 0, sel_time.tm_sec, 60, 1, 1);
+                        sel_time.tm_min = nk_propertyi(ctx, "#M:", 0, sel_time.tm_min, 60, 1, 1);
+                        sel_time.tm_hour = nk_propertyi(ctx, "#H:", 0, sel_time.tm_hour, 23, 1, 1);
+                        nk_combo_end(ctx);
+                    }
+
+                    /* date combobox */
+                    nk_layout_row_static(ctx, 25, 350, 1);
+                    sprintf(buffer, "%02d-%02d-%02d", sel_date.tm_mday, sel_date.tm_mon+1, sel_date.tm_year+1900);
+                    if (nk_combo_begin_label(ctx, &combo, buffer, 400))
+                    {
+                        int i = 0;
+                        const char *month[] = {"January", "February", "March", "Apil", "May", "June", "July", "August", "September", "Ocotober", "November", "December"};
+                        const char *week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
+                        const int month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+                        int year = sel_date.tm_year+1900;
+                        int leap_year = (!(year % 4) && ((year % 100))) || !(year % 400);
+                        int days = (sel_date.tm_mon == 1) ?
+                            month_days[sel_date.tm_mon] + leap_year:
+                            month_days[sel_date.tm_mon];
+
+                        /* header with month and year */
+                        date_selected = 1;
+                        nk_layout_row_begin(ctx, NK_DYNAMIC, 20, 3);
+                        nk_layout_row_push(ctx, 0.05f);
+                        if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT, NK_BUTTON_DEFAULT)) {
+                            if (sel_date.tm_mon == 0) {
+                                sel_date.tm_mon = 11;
+                                sel_date.tm_year = MAX(0, sel_date.tm_year-1);
+                            } else sel_date.tm_mon--;
+                        }
+                        nk_layout_row_push(ctx, 0.9f);
+                        sprintf(buffer, "%s %d", month[sel_date.tm_mon], year);
+                        nk_label(ctx, buffer, NK_TEXT_CENTERED);
+                        nk_layout_row_push(ctx, 0.05f);
+                        if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT, NK_BUTTON_DEFAULT)) {
+                            if (sel_date.tm_mon == 11) {
+                                sel_date.tm_mon = 0;
+                                sel_date.tm_year++;
+                            } else sel_date.tm_mon++;
+                        }
+                        nk_layout_row_end(ctx);
+
+                        /* good old week day formula (double because precision) */
+                        {int year_n = (sel_date.tm_mon < 2) ? year-1: year;
+                        int y = year_n % 100;
+                        int c = year_n / 100;
+                        int y4 = (int)((float)y / 4);
+                        int c4 = (int)((float)c / 4);
+                        int m = (int)(2.6 * (double)(((sel_date.tm_mon + 10) % 12) + 1) - 0.2);
+                        int week_day = (((1 + m + y + y4 + c4 - 2 * c) % 7) + 7) % 7;
+
+                        /* weekdays  */
+                        nk_layout_row_dynamic(ctx, 35, 7);
+                        for (i = 0; i < (int)LEN(week_days); ++i)
+                            nk_label(ctx, week_days[i], NK_TEXT_CENTERED);
+
+                        /* days  */
+                        if (week_day > 0) nk_spacing(ctx, week_day);
+                        for (i = 1; i <= days; ++i) {
+                            sprintf(buffer, "%d", i);
+                            if (nk_button_label(ctx, buffer, NK_BUTTON_DEFAULT)) {
+                                sel_date.tm_mday = i;
+                                nk_combo_close(ctx);
+                            }
+                        }}
+                        nk_combo_end(ctx);
+                    }
+                }
+
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Input", NK_MINIMIZED))
+            {
+                static const float ratio[] = {120, 150};
+                static char field_buffer[64];
+                static char text[9][64];
+                static int text_len[9];
+                static char box_buffer[512];
+                static int field_len;
+                static int box_len;
+                nk_flags active;
+
+                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+                nk_label(ctx, "Default:", NK_TEXT_LEFT);
+
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[0], &text_len[0], 64, nk_filter_default);
+                nk_label(ctx, "Int:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[1], &text_len[1], 64, nk_filter_decimal);
+                nk_label(ctx, "Float:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[2], &text_len[2], 64, nk_filter_float);
+                nk_label(ctx, "Hex:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[4], &text_len[4], 64, nk_filter_hex);
+                nk_label(ctx, "Octal:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[5], &text_len[5], 64, nk_filter_oct);
+                nk_label(ctx, "Binary:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[6], &text_len[6], 64, nk_filter_binary);
+
+                nk_label(ctx, "Password:", NK_TEXT_LEFT);
+                {
+                    int i = 0;
+                    int old_len = text_len[8];
+                    char buffer[64];
+                    for (i = 0; i < text_len[8]; ++i) buffer[i] = '*';
+                    nk_edit_string(ctx, NK_EDIT_FIELD, buffer, &text_len[8], 64, nk_filter_default);
+                    if (old_len < text_len[8])
+                        memcpy(&text[8][old_len], &buffer[old_len], (nk_size)(text_len[8] - old_len));
+                }
+
+                nk_label(ctx, "Field:", NK_TEXT_LEFT);
+                nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);
+
+                nk_label(ctx, "Box:", NK_TEXT_LEFT);
+                nk_layout_row_static(ctx, 180, 278, 1);
+                nk_edit_string(ctx, NK_EDIT_BOX, box_buffer, &box_len, 512, nk_filter_default);
+
+                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+                active = nk_edit_string(ctx, NK_EDIT_FIELD|NK_EDIT_SIG_ENTER, text[7], &text_len[7], 64,  nk_filter_ascii);
+                if (nk_button_label(ctx, "Submit", NK_BUTTON_DEFAULT) ||
+                    (active & NK_EDIT_COMMITED))
+                {
+                    text[7][text_len[7]] = '\n';
+                    text_len[7]++;
+                    memcpy(&box_buffer[box_len], &text[7], (nk_size)text_len[7]);
+                    box_len += text_len[7];
+                    text_len[7] = 0;
+                }
+                nk_layout_row_end(ctx);
+                nk_tree_pop(ctx);
+            }
+            nk_tree_pop(ctx);
+        }
+
+        if (nk_tree_push(ctx, NK_TREE_TAB, "Chart", NK_MINIMIZED))
+        {
+            /* Chart Widgets
+             * This library has two different rather simple charts. The line and the
+             * column chart. Both provide a simple way of visualizing values and
+             * have a retain mode and immedidate mode API version. For the retain
+             * mode version `nk_plot` and `nk_plot_function` you either provide
+             * an array or a callback to call to handle drawing the graph.
+             * For the immediate mode version you start by calling `nk_chart_begin`
+             * and need to provide min and max values for scaling on the Y-axis.
+             * and then call `nk_chart_push` to push values into the chart.
+             * Finally `nk_chart_end` needs to be called to end the process. */
+            float id = 0;
+            static int col_index = -1;
+            static int line_index = -1;
+            float step = (2*3.141592654f) / 32;
+
+            int i;
+            int index = -1;
+            struct nk_rect bounds;
+
+            /* line chart */
+            id = 0;
+            index = -1;
+            nk_layout_row_dynamic(ctx, 100, 1);
+            bounds = nk_widget_bounds(ctx);
+            if (nk_chart_begin(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f)) {
+                for (i = 0; i < 32; ++i) {
+                    nk_flags res = nk_chart_push(ctx, (float)cos(id));
+                    if (res & NK_CHART_HOVERING)
+                        index = (int)i;
+                    if (res & NK_CHART_CLICKED)
+                        line_index = (int)i;
+                    id += step;
+                }
+                nk_chart_end(ctx);
+            }
+
+            if (index != -1) {
+                char buffer[NK_MAX_NUMBER_BUFFER];
+                float val = (float)cos((float)index*step);
+                sprintf(buffer, "Value: %.2f", val);
+                nk_tooltip(ctx, buffer);
+            }
+            if (line_index != -1) {
+                nk_layout_row_dynamic(ctx, 20, 1);
+                nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)cos((float)index*step));
+            }
+
+            /* column chart */
+            nk_layout_row_dynamic(ctx, 100, 1);
+            bounds = nk_widget_bounds(ctx);
+            if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) {
+                for (i = 0; i < 32; ++i) {
+                    nk_flags res = nk_chart_push(ctx, (float)fabs(sin(id)));
+                    if (res & NK_CHART_HOVERING)
+                        index = (int)i;
+                    if (res & NK_CHART_CLICKED)
+                        col_index = (int)i;
+                    id += step;
+                }
+                nk_chart_end(ctx);
+            }
+            if (index != -1) {
+                char buffer[NK_MAX_NUMBER_BUFFER];
+                sprintf(buffer, "Value: %.2f", (float)fabs(sin(step * (float)index)));
+                nk_tooltip(ctx, buffer);
+            }
+            if (col_index != -1) {
+                nk_layout_row_dynamic(ctx, 20, 1);
+                nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)fabs(sin(step * (float)col_index)));
+            }
+            nk_tree_pop(ctx);
+        }
+
+        if (nk_tree_push(ctx, NK_TREE_TAB, "Popup", NK_MINIMIZED))
+        {
+            static struct nk_color color = {255,0,0, 255};
+            static int select[4];
+            static int popup_active;
+            const struct nk_input *in = &ctx->input;
+            struct nk_rect bounds;
+
+            /* menu contextual */
+            nk_layout_row_static(ctx, 30, 150, 1);
+            bounds = nk_widget_bounds(ctx);
+            nk_label(ctx, "Right click me for menu", NK_TEXT_LEFT);
+
+            if (nk_contextual_begin(ctx, &menu, 0, nk_vec2(100, 300), bounds)) {
+                static size_t prog = 40;
+                static int slider = 10;
+
+                nk_layout_row_dynamic(ctx, 25, 1);
+                nk_checkbox_label(ctx, "Menu", &show_menu);
+                nk_progress(ctx, &prog, 100, NK_MODIFIABLE);
+                nk_slider_int(ctx, 0, &slider, 16, 1);
+                if (nk_contextual_item_label(ctx, "About", NK_TEXT_CENTERED))
+                    show_app_about = nk_true;
+                nk_selectable_label(ctx, select[0]?"Unselect":"Select", NK_TEXT_LEFT, &select[0]);
+                nk_selectable_label(ctx, select[1]?"Unselect":"Select", NK_TEXT_LEFT, &select[1]);
+                nk_selectable_label(ctx, select[2]?"Unselect":"Select", NK_TEXT_LEFT, &select[2]);
+                nk_selectable_label(ctx, select[3]?"Unselect":"Select", NK_TEXT_LEFT, &select[3]);
+                nk_contextual_end(ctx);
+            }
+
+            /* color contextual */
+            nk_layout_row_begin(ctx, NK_STATIC, 30, 2);
+            nk_layout_row_push(ctx, 100);
+            nk_label(ctx, "Right Click here:", NK_TEXT_LEFT);
+            nk_layout_row_push(ctx, 50);
+            bounds = nk_widget_bounds(ctx);
+            nk_button_color(ctx, color, NK_BUTTON_DEFAULT);
+            nk_layout_row_end(ctx);
+
+            if (nk_contextual_begin(ctx, &menu, 0, nk_vec2(350, 60), bounds)) {
+                nk_layout_row_dynamic(ctx, 30, 4);
+                color.r = (nk_byte)nk_propertyi(ctx, "#r", 0, color.r, 255, 1, 1);
+                color.g = (nk_byte)nk_propertyi(ctx, "#g", 0, color.g, 255, 1, 1);
+                color.b = (nk_byte)nk_propertyi(ctx, "#b", 0, color.b, 255, 1, 1);
+                color.a = (nk_byte)nk_propertyi(ctx, "#a", 0, color.a, 255, 1, 1);
+                nk_contextual_end(ctx);
+            }
+
+            /* popup */
+            nk_layout_row_begin(ctx, NK_STATIC, 30, 2);
+            nk_layout_row_push(ctx, 100);
+            nk_label(ctx, "Popup:", NK_TEXT_LEFT);
+            nk_layout_row_push(ctx, 50);
+            if (nk_button_label(ctx, "Popup", NK_BUTTON_DEFAULT))
+                popup_active = 1;
+            nk_layout_row_end(ctx);
+
+            if (popup_active)
+            {
+                static struct nk_rect s = {20, 100, 220, 150};
+                if (nk_popup_begin(ctx, &menu, NK_POPUP_STATIC, "Error", NK_WINDOW_DYNAMIC, s))
+                {
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    nk_label(ctx, "A terrible error as occured", NK_TEXT_LEFT);
+                    nk_layout_row_dynamic(ctx, 25, 2);
+                    if (nk_button_label(ctx, "OK", NK_BUTTON_DEFAULT)) {
+                        popup_active = 0;
+                        nk_popup_close(ctx);
+                    }
+                    if (nk_button_label(ctx, "Cancel", NK_BUTTON_DEFAULT)) {
+                        popup_active = 0;
+                        nk_popup_close(ctx);
+                    }
+                    nk_popup_end(ctx);
+                } else popup_active = nk_false;
+            }
+
+            /* tooltip */
+            nk_layout_row_static(ctx, 30, 150, 1);
+            bounds = nk_widget_bounds(ctx);
+            nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT);
+            if (nk_input_is_mouse_hovering_rect(in, bounds))
+                nk_tooltip(ctx, "This is a tooltip");
+
+            nk_tree_pop(ctx);
+        }
+
+        if (nk_tree_push(ctx, NK_TREE_TAB, "Layout", NK_MINIMIZED))
+        {
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Widget", NK_MINIMIZED))
+            {
+                float ratio_two[] = {0.2f, 0.6f, 0.2f};
+                float width_two[] = {100, 200, 50};
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Dynamic fixed column layout with generated position and size:", NK_TEXT_LEFT);
+                nk_layout_row_dynamic(ctx, 30, 3);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "static fixed column layout with generated position and size:", NK_TEXT_LEFT);
+                nk_layout_row_static(ctx, 30, 100, 3);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Dynamic array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT);
+                nk_layout_row(ctx, NK_DYNAMIC, 30, 3, ratio_two);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Static array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT );
+                nk_layout_row(ctx, NK_STATIC, 30, 3, width_two);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Dynamic immediate mode custom column layout with generated position and custom size:",NK_TEXT_LEFT);
+                nk_layout_row_begin(ctx, NK_DYNAMIC, 30, 3);
+                nk_layout_row_push(ctx, 0.2f);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_push(ctx, 0.6f);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_push(ctx, 0.2f);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_end(ctx);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Static immmediate mode custom column layout with generated position and custom size:", NK_TEXT_LEFT);
+                nk_layout_row_begin(ctx, NK_STATIC, 30, 3);
+                nk_layout_row_push(ctx, 100);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_push(ctx, 200);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_push(ctx, 50);
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_row_end(ctx);
+
+                nk_layout_row_dynamic(ctx, 30, 1);
+                nk_label(ctx, "Static free space with custom position and custom size:", NK_TEXT_LEFT);
+                nk_layout_space_begin(ctx, NK_STATIC, 120, 4);
+                nk_layout_space_push(ctx, nk_rect(100, 0, 100, 30));
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_space_push(ctx, nk_rect(0, 15, 100, 30));
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_space_push(ctx, nk_rect(200, 15, 100, 30));
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_space_push(ctx, nk_rect(100, 30, 100, 30));
+                nk_button_label(ctx, "button", NK_BUTTON_DEFAULT);
+                nk_layout_space_end(ctx);
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Group", NK_MINIMIZED))
+            {
+                static int group_titlebar = nk_false;
+                static int group_border = nk_true;
+                static int group_no_scrollbar = nk_false;
+                static int group_width = 320;
+                static int group_height = 200;
+                struct nk_panel tab;
+
+                nk_flags group_flags = 0;
+                if (group_border) group_flags |= NK_WINDOW_BORDER;
+                if (group_no_scrollbar) group_flags |= NK_WINDOW_NO_SCROLLBAR;
+                if (group_titlebar) group_flags |= NK_WINDOW_TITLE;
+
+                nk_layout_row_dynamic(ctx, 30, 3);
+                nk_checkbox_label(ctx, "Titlebar", &group_titlebar);
+                nk_checkbox_label(ctx, "Border", &group_border);
+                nk_checkbox_label(ctx, "No Scrollbar", &group_no_scrollbar);
+
+                nk_layout_row_begin(ctx, NK_STATIC, 22, 2);
+                nk_layout_row_push(ctx, 50);
+                nk_label(ctx, "size:", NK_TEXT_LEFT);
+                nk_layout_row_push(ctx, 130);
+                nk_property_int(ctx, "#Width:", 100, &group_width, 500, 10, 1);
+                nk_layout_row_push(ctx, 130);
+                nk_property_int(ctx, "#Height:", 100, &group_height, 500, 10, 1);
+                nk_layout_row_end(ctx);
+
+                nk_layout_row_static(ctx, (float)group_height, group_width, 2);
+                if (nk_group_begin(ctx, &tab, "Group", group_flags)) {
+                    int i = 0;
+                    static int selected[16];
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    for (i = 0; i < 16; ++i)
+                        nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+                    nk_group_end(ctx);
+                }
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Simple", NK_MINIMIZED))
+            {
+                struct nk_panel tab;
+                nk_layout_row_dynamic(ctx, 300, 2);
+                if (nk_group_begin(ctx, &tab, "Group_Without_Border", 0)) {
+                    int i = 0;
+                    char buffer[64];
+                    nk_layout_row_static(ctx, 18, 150, 1);
+                    for (i = 0; i < 64; ++i) {
+                        sprintf(buffer, "0x%02x", i);
+                        nk_labelf(ctx, NK_TEXT_LEFT, "%s: scrollable region", buffer);
+                    }
+                    nk_group_end(ctx);
+                }
+                if (nk_group_begin(ctx, &tab, "Group_With_Border", NK_WINDOW_BORDER)) {
+                    int i = 0;
+                    char buffer[64];
+                    nk_layout_row_dynamic(ctx, 25, 2);
+                    for (i = 0; i < 64; ++i) {
+                        sprintf(buffer, "%08d", ((((i%7)*10)^32))+(64+(i%2)*2));
+                        nk_button_label(ctx, buffer, NK_BUTTON_DEFAULT);
+                    }
+                    nk_group_end(ctx);
+                }
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Complex", NK_MINIMIZED))
+            {
+                int i;
+                struct nk_panel tab;
+                nk_layout_space_begin(ctx, NK_STATIC, 500, 64);
+                nk_layout_space_push(ctx, nk_rect(0,0,150,500));
+                if (nk_group_begin(ctx, &tab, "Group_left", NK_WINDOW_BORDER)) {
+                    static int selected[32];
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    for (i = 0; i < 32; ++i)
+                        nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+                    nk_group_end(ctx);
+                }
+
+                nk_layout_space_push(ctx, nk_rect(160,0,150,240));
+                if (nk_group_begin(ctx, &tab, "Group_top", NK_WINDOW_BORDER)) {
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                    nk_group_end(ctx);
+                }
+
+                nk_layout_space_push(ctx, nk_rect(160,250,150,250));
+                if (nk_group_begin(ctx, &tab, "Group_buttom", NK_WINDOW_BORDER)) {
+                    nk_layout_row_dynamic(ctx, 25, 1);
+                    nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                    nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                    nk_group_end(ctx);
+                }
+
+                nk_layout_space_push(ctx, nk_rect(320,0,150,150));
+                if (nk_group_begin(ctx, &tab, "Group_right_top", NK_WINDOW_BORDER)) {
+                    static int selected[4];
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    for (i = 0; i < 4; ++i)
+                        nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+                    nk_group_end(ctx);
+                }
+
+                nk_layout_space_push(ctx, nk_rect(320,160,150,150));
+                if (nk_group_begin(ctx, &tab, "Group_right_center", NK_WINDOW_BORDER)) {
+                    static int selected[4];
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    for (i = 0; i < 4; ++i)
+                        nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+                    nk_group_end(ctx);
+                }
+
+                nk_layout_space_push(ctx, nk_rect(320,320,150,150));
+                if (nk_group_begin(ctx, &tab, "Group_right_bottom", NK_WINDOW_BORDER)) {
+                    static int selected[4];
+                    nk_layout_row_static(ctx, 18, 100, 1);
+                    for (i = 0; i < 4; ++i)
+                        nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+                    nk_group_end(ctx);
+                }
+                nk_layout_space_end(ctx);
+                nk_tree_pop(ctx);
+            }
+
+            if (nk_tree_push(ctx, NK_TREE_NODE, "Splitter", NK_MINIMIZED))
+            {
+                const struct nk_input *in = &ctx->input;
+                nk_layout_row_static(ctx, 20, 320, 1);
+                nk_label(ctx, "Use slider and spinner to change tile size", NK_TEXT_LEFT);
+                nk_label(ctx, "Drag the space between tiles to change tile ratio", NK_TEXT_LEFT);
+
+                if (nk_tree_push(ctx, NK_TREE_NODE, "Vertical", NK_MINIMIZED))
+                {
+                    static float a = 100, b = 100, c = 100;
+                    struct nk_rect bounds;
+                    struct nk_panel sub;
+
+                    float row_layout[5];
+                    row_layout[0] = a;
+                    row_layout[1] = 8;
+                    row_layout[2] = b;
+                    row_layout[3] = 8;
+                    row_layout[4] = c;
+
+                    /* header */
+                    nk_layout_row_static(ctx, 30, 100, 2);
+                    nk_label(ctx, "left:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
+
+                    nk_label(ctx, "middle:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
+
+                    nk_label(ctx, "right:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
+
+                    /* tiles */
+                    nk_layout_row(ctx, NK_STATIC, 200, 5, row_layout);
+
+                    /* left space */
+                    if (nk_group_begin(ctx, &sub, "left", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+                        nk_layout_row_dynamic(ctx, 25, 1);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+
+                    /* scaler */
+                    bounds = nk_widget_bounds(ctx);
+                    nk_spacing(ctx, 1);
+                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+                    {
+                        a = row_layout[0] + in->mouse.delta.x;
+                        b = row_layout[2] - in->mouse.delta.x;
+                    }
+
+                    /* middle space */
+                    if (nk_group_begin(ctx, &sub, "center", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+                        nk_layout_row_dynamic(ctx, 25, 1);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+
+                    /* scaler */
+                    bounds = nk_widget_bounds(ctx);
+                    nk_spacing(ctx, 1);
+                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+                    {
+                        b = (row_layout[2] + in->mouse.delta.x);
+                        c = (row_layout[4] - in->mouse.delta.x);
+                    }
+
+                    /* right space */
+                    if (nk_group_begin(ctx, &sub, "right", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+                        nk_layout_row_dynamic(ctx, 25, 1);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+
+                    nk_tree_pop(ctx);
+                }
+
+                if (nk_tree_push(ctx, NK_TREE_NODE, "Horizontal", NK_MINIMIZED))
+                {
+                    static float a = 100, b = 100, c = 100;
+                    struct nk_panel sub;
+                    struct nk_rect bounds;
+
+                    /* header */
+                    nk_layout_row_static(ctx, 30, 100, 2);
+                    nk_label(ctx, "top:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
+
+                    nk_label(ctx, "middle:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
+
+                    nk_label(ctx, "bottom:", NK_TEXT_LEFT);
+                    nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
+
+                    /* top space */
+                    nk_layout_row_dynamic(ctx, a, 1);
+                    if (nk_group_begin(ctx, &sub, "top", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+                        nk_layout_row_dynamic(ctx, 25, 3);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+
+                    /* scaler */
+                    nk_layout_row_dynamic(ctx, 8, 1);
+                    bounds = nk_widget_bounds(ctx);
+                    nk_spacing(ctx, 1);
+                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+                    {
+                        a = a + in->mouse.delta.y;
+                        b = b - in->mouse.delta.y;
+                    }
+
+                    /* middle space */
+                    nk_layout_row_dynamic(ctx, b, 1);
+                    if (nk_group_begin(ctx, &sub, "middle", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+                        nk_layout_row_dynamic(ctx, 25, 3);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+
+                    {
+                        /* scaler */
+                        nk_layout_row_dynamic(ctx, 8, 1);
+                        bounds = nk_widget_bounds(ctx);
+                        if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+                            nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+                            nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+                        {
+                            b = b + in->mouse.delta.y;
+                            c = c - in->mouse.delta.y;
+                        }
+                    }
+
+                    /* bottom space */
+                    nk_layout_row_dynamic(ctx, c, 1);
+                    if (nk_group_begin(ctx, &sub, "bottom", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+                        nk_layout_row_dynamic(ctx, 25, 3);
+                        nk_button_label(ctx, "#FFAA", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFBB", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFCC", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFDD", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFEE", NK_BUTTON_DEFAULT);
+                        nk_button_label(ctx, "#FFFF", NK_BUTTON_DEFAULT);
+                        nk_group_end(ctx);
+                    }
+                    nk_tree_pop(ctx);
+                }
+                nk_tree_pop(ctx);
+            }
+            nk_tree_pop(ctx);
+        }
+    }
+    nk_end(ctx);
+    return !nk_window_is_closed(ctx, "Demo");
+}
+
+/* ===============================================================
+ *
+ *                          DEVICE
+ *
+ * ===============================================================*/
+struct device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+
+static void
+device_init(struct device *dev)
+{
+    GLint status;
+    static const GLchar *vertex_shader =
+        "#version 300 es\n"
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    nk_buffer_init_default(&dev->cmds);
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_draw_vertex);
+        size_t vp = offsetof(struct nk_draw_vertex, position);
+        size_t vt = offsetof(struct nk_draw_vertex, uv);
+        size_t vc = offsetof(struct nk_draw_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->frag_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+    enum nk_anti_aliasing AA)
+{
+    GLint last_prog, last_tex;
+    GLint last_ebo, last_vbo, last_vao;
+    GLfloat ortho[4][4] = {
+        {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},
+    };
+    ortho[0][0] /= (GLfloat)width;
+    ortho[1][1] /= (GLfloat)height;
+
+    /* save previous opengl state */
+    glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
+    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
+    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
+    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
+    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
+
+    /* setup global state */
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+        /* load draw vertices & elements directly into vertex + element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = dev->null;
+
+            /* setup buffers to load vertices and elements */
+            {struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, ctx, &dev->cmds) {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor((GLint)cmd->clip_rect.x,
+                height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
+                (GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(ctx);
+    }
+
+    /* restore old state */
+    glUseProgram((GLuint)last_prog);
+    glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
+    glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
+    glBindVertexArray((GLuint)last_vao);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+    /* Platform */
+    static GLFWwindow *win;
+    int width = 0, height = 0;
+
+    /* GUI */
+    struct device device;
+    struct nk_context ctx;
+    struct nk_font *font;
+    struct nk_font_atlas atlas;
+
+    /* GLFW */
+    glfwSetErrorCallback(error_callback);
+    if (!glfwInit()) {
+        fprintf(stdout, "[GFLW] failed to init!\n");
+        exit(1);
+    }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+    glfwMakeContextCurrent(win);
+    glfwSetWindowUserPointer(win, &ctx);
+    glfwSetCharCallback(win, text_input);
+    glfwSetScrollCallback(win, scroll_input);
+
+    /* OpenGL */
+    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    glewExperimental = 1;
+    if (glewInit() != GLEW_OK) {
+        fprintf(stderr, "Failed to setup GLEW\n");
+        exit(1);
+    }
+
+    {/* GUI */
+    device_init(&device);
+    {const void *image; int w, h;
+    const char *font_path = (argc > 1) ? argv[1]: 0;
+    nk_font_atlas_init_default(&atlas);
+    nk_font_atlas_begin(&atlas);
+    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
+    else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
+    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    device_upload_atlas(&device, image, w, h);
+    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+    nk_init_default(&ctx, &font->handle);}
+
+    while (!glfwWindowShouldClose(win))
+    {
+        /* Input */
+        {double x, y;
+        nk_input_begin(&ctx);
+        glfwPollEvents();
+        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
+            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+        } else {
+            nk_input_key(&ctx, NK_KEY_COPY, 0);
+            nk_input_key(&ctx, NK_KEY_PASTE, 0);
+            nk_input_key(&ctx, NK_KEY_CUT, 0);
+            nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+        }
+        glfwGetCursorPos(win, &x, &y);
+        nk_input_motion(&ctx, (int)x, (int)y);
+        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+        nk_input_end(&ctx);}
+
+        /* GUI */
+        if (!overview_window(&ctx)) break;
+
+        /* Draw */
+        glfwGetWindowSize(win, &width, &height);
+        glViewport(0, 0, width, height);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+        device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
+        glfwSwapBuffers(win);
+    }
+
+    nk_font_atlas_clear(&atlas);
+    nk_free(&ctx);
+    device_shutdown(&device);
+    glfwTerminate();
+    return 0;
+}
+

+ 0 - 0
demo/stb_image.h → example/stb_image.h


+ 132 - 0
example/style.c

@@ -0,0 +1,132 @@
+enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK};
+
+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);
+        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);
+        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);
+        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);
+        nk_style_from_table(ctx, table);
+    } else {
+        nk_style_default(ctx);
+    }
+}
+
+

BIN
extra_font/Cousine-Regular.ttf


+ 0 - 0
font/DroidSans.ttf → extra_font/DroidSans.ttf


BIN
extra_font/Karla-Regular.ttf


BIN
extra_font/ProggyClean.ttf


BIN
extra_font/ProggyTiny.ttf


BIN
extra_font/Raleway-Bold.ttf


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