aboutsummaryrefslogtreecommitdiff
path: root/nuklear
diff options
context:
space:
mode:
Diffstat (limited to 'nuklear')
-rw-r--r--nuklear/.gitattributes3
-rw-r--r--nuklear/.gitignore2
-rw-r--r--nuklear/.travis.yml16
-rw-r--r--nuklear/CHANGELOG.md190
-rw-r--r--nuklear/Readme.md111
-rw-r--r--nuklear/demo/calculator.c64
-rw-r--r--nuklear/demo/d3d11/build.bat9
-rw-r--r--nuklear/demo/d3d11/main.c278
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11.h617
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11.hlsl36
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h179
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h350
-rw-r--r--nuklear/demo/gdi/build.bat6
-rw-r--r--nuklear/demo/gdi/main.c161
-rw-r--r--nuklear/demo/gdi/nuklear_gdi.h761
-rw-r--r--nuklear/demo/gdip/build.bat5
-rw-r--r--nuklear/demo/gdip/main.c155
-rw-r--r--nuklear/demo/gdip/nuklear_gdip.h1006
-rw-r--r--nuklear/demo/glfw_opengl2/Makefile25
-rw-r--r--nuklear/demo/glfw_opengl2/main.c165
-rw-r--r--nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h350
-rw-r--r--nuklear/demo/glfw_opengl3/Makefile25
-rw-r--r--nuklear/demo/glfw_opengl3/main.c180
-rw-r--r--nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h456
-rw-r--r--nuklear/demo/node_editor.c343
-rw-r--r--nuklear/demo/overview.c1188
-rw-r--r--nuklear/demo/sdl_opengl2/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl2/main.c181
-rw-r--r--nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h342
-rw-r--r--nuklear/demo/sdl_opengl3/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl3/main.c195
-rw-r--r--nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h437
-rw-r--r--nuklear/demo/style.c132
-rw-r--r--nuklear/demo/x11/Makefile13
-rw-r--r--nuklear/demo/x11/main.c203
-rw-r--r--nuklear/demo/x11/nuklear_xlib.h693
-rw-r--r--nuklear/demo/x11_opengl2/Makefile26
-rw-r--r--nuklear/demo/x11_opengl2/main.c320
-rw-r--r--nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h357
-rw-r--r--nuklear/demo/x11_opengl3/Makefile26
-rw-r--r--nuklear/demo/x11_opengl3/main.c317
-rw-r--r--nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h725
-rw-r--r--nuklear/example/Makefile41
-rw-r--r--nuklear/example/canvas.c489
-rw-r--r--nuklear/example/extended.c906
-rw-r--r--nuklear/example/file_browser.c910
-rw-r--r--nuklear/example/icon/checked.pngbin0 -> 1813 bytes
-rw-r--r--nuklear/example/icon/cloud.pngbin0 -> 7509 bytes
-rw-r--r--nuklear/example/icon/computer.pngbin0 -> 620 bytes
-rw-r--r--nuklear/example/icon/copy.pngbin0 -> 655 bytes
-rw-r--r--nuklear/example/icon/default.pngbin0 -> 460 bytes
-rw-r--r--nuklear/example/icon/delete.pngbin0 -> 11040 bytes
-rw-r--r--nuklear/example/icon/desktop.pngbin0 -> 583 bytes
-rw-r--r--nuklear/example/icon/directory.pngbin0 -> 533 bytes
-rw-r--r--nuklear/example/icon/edit.pngbin0 -> 14998 bytes
-rw-r--r--nuklear/example/icon/export.pngbin0 -> 13336 bytes
-rw-r--r--nuklear/example/icon/font.pngbin0 -> 561 bytes
-rw-r--r--nuklear/example/icon/home.pngbin0 -> 819 bytes
-rw-r--r--nuklear/example/icon/img.pngbin0 -> 648 bytes
-rw-r--r--nuklear/example/icon/movie.pngbin0 -> 626 bytes
-rw-r--r--nuklear/example/icon/music.pngbin0 -> 610 bytes
-rw-r--r--nuklear/example/icon/next.pngbin0 -> 703 bytes
-rw-r--r--nuklear/example/icon/pause.pngbin0 -> 1338 bytes
-rw-r--r--nuklear/example/icon/pen.pngbin0 -> 5949 bytes
-rw-r--r--nuklear/example/icon/phone.pngbin0 -> 15778 bytes
-rw-r--r--nuklear/example/icon/plane.pngbin0 -> 13546 bytes
-rw-r--r--nuklear/example/icon/play.pngbin0 -> 566 bytes
-rw-r--r--nuklear/example/icon/prev.pngbin0 -> 701 bytes
-rw-r--r--nuklear/example/icon/rocket.pngbin0 -> 1121 bytes
-rw-r--r--nuklear/example/icon/settings.pngbin0 -> 15671 bytes
-rw-r--r--nuklear/example/icon/stop.pngbin0 -> 520 bytes
-rw-r--r--nuklear/example/icon/text.pngbin0 -> 601 bytes
-rw-r--r--nuklear/example/icon/tools.pngbin0 -> 24483 bytes
-rw-r--r--nuklear/example/icon/unchecked.pngbin0 -> 1044 bytes
-rw-r--r--nuklear/example/icon/volume.pngbin0 -> 25438 bytes
-rw-r--r--nuklear/example/icon/wifi.pngbin0 -> 18857 bytes
-rw-r--r--nuklear/example/images/image1.pngbin0 -> 42882 bytes
-rw-r--r--nuklear/example/images/image2.pngbin0 -> 5671 bytes
-rw-r--r--nuklear/example/images/image3.pngbin0 -> 131502 bytes
-rw-r--r--nuklear/example/images/image4.pngbin0 -> 185821 bytes
-rw-r--r--nuklear/example/images/image5.pngbin0 -> 98475 bytes
-rw-r--r--nuklear/example/images/image6.pngbin0 -> 35633 bytes
-rw-r--r--nuklear/example/images/image7.pngbin0 -> 13960 bytes
-rw-r--r--nuklear/example/images/image8.pngbin0 -> 45987 bytes
-rw-r--r--nuklear/example/images/image9.pngbin0 -> 30759 bytes
-rw-r--r--nuklear/example/skinning.c825
-rw-r--r--nuklear/example/skins/gwen.pngbin0 -> 24565 bytes
-rw-r--r--nuklear/example/stb_image.h6509
-rw-r--r--nuklear/extra_font/Cousine-Regular.ttfbin0 -> 43912 bytes
-rw-r--r--nuklear/extra_font/DroidSans.ttfbin0 -> 190044 bytes
-rw-r--r--nuklear/extra_font/Karla-Regular.ttfbin0 -> 16848 bytes
-rw-r--r--nuklear/extra_font/ProggyClean.ttfbin0 -> 41208 bytes
-rw-r--r--nuklear/extra_font/ProggyTiny.ttfbin0 -> 35656 bytes
-rw-r--r--nuklear/extra_font/Raleway-Bold.ttfbin0 -> 176280 bytes
-rw-r--r--nuklear/extra_font/Roboto-Bold.ttfbin0 -> 135820 bytes
-rw-r--r--nuklear/extra_font/Roboto-Light.ttfbin0 -> 140276 bytes
-rw-r--r--nuklear/extra_font/Roboto-Regular.ttfbin0 -> 145348 bytes
-rw-r--r--nuklear/extra_font/kenvector_future.ttfbin0 -> 34136 bytes
-rw-r--r--nuklear/extra_font/kenvector_future_thin.ttfbin0 -> 34100 bytes
-rw-r--r--nuklear/nuklear.h22128
-rw-r--r--nuklear/package.json8
101 files changed, 42514 insertions, 0 deletions
diff --git a/nuklear/.gitattributes b/nuklear/.gitattributes
new file mode 100644
index 0000000..5a5328c
--- /dev/null
+++ b/nuklear/.gitattributes
@@ -0,0 +1,3 @@
+# Github language settings
+*.h linguist-language=c
+*.c linguist-language=c
diff --git a/nuklear/.gitignore b/nuklear/.gitignore
new file mode 100644
index 0000000..a9f3b63
--- /dev/null
+++ b/nuklear/.gitignore
@@ -0,0 +1,2 @@
+demo/*/*.exe
+demo/*/*.obj
diff --git a/nuklear/.travis.yml b/nuklear/.travis.yml
new file mode 100644
index 0000000..7df45b3
--- /dev/null
+++ b/nuklear/.travis.yml
@@ -0,0 +1,16 @@
+language: c
+
+os:
+ - linux
+ - osx
+
+compiler:
+ - gcc
+ - clang
+
+before_install:
+ - if [ $TRAVIS_OS_NAME == linux ]; then sudo add-apt-repository -y ppa:pyglfw/pyglfw && sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libglfw3 libglfw3-dev libglew-dev; fi
+ - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install glfw3 && brew install glew; fi
+
+script:
+ - make -C demo/glfw_opengl3
diff --git a/nuklear/CHANGELOG.md b/nuklear/CHANGELOG.md
new file mode 100644
index 0000000..17f1858
--- /dev/null
+++ b/nuklear/CHANGELOG.md
@@ -0,0 +1,190 @@
+# Changelog
+- 2016/12/03 (1.191)- Fixed wrapped text with no seperator and C89 error
+- 2016/12/03 (1.19) - Changed text wrapping to process words not characters
+- 2016/11/22 (1.184)- Fixed window minimized closing bug
+- 2016/11/19 (1.184)- Fixed abstract combo box closing behavior
+- 2016/11/19 (1.184)- Fixed tooltip flickering
+- 2016/11/19 (1.183)- Fixed memory leak caused by popup repeated closing
+- 2016/11/18 (1.182)- Fixed memory leak caused by popup panel allocation
+- 2016/11/10 (1.181)- Fixed some warnings and C++ error
+- 2016/11/10 (1.180)- Added additional `nk_button` versions which allows to directly
+ pass in a style struct to change buttons visual.
+- 2016/11/10 (1.180)- Added additional 'nk_tree' versions to support external state
+ storage. Just like last the `nk_group` commit the main
+ advantage is that you optionally can minimize nuklears runtime
+ memory consumption or handle hash collisions.
+- 2016/11/09 (1.180)- Added additional `nk_group` version to support external scrollbar
+ offset storage. Main advantage is that you can externalize
+ the memory management for the offset. It could also be helpful
+ if you have a hash collision in `nk_group_begin` but really
+ want the name. In addition I added `nk_list_view` which allows
+ to draw big lists inside a group without actually having to
+ commit the whole list to nuklear (issue #269).
+- 2016/10/30 (1.171)- Fixed clipping rectangle bug inside `nk_draw_list`
+- 2016/10/29 (1.170)- Pulled `nk_panel` memory management into nuklear and out of
+ the hands of the user. From now on users don't have to care
+ about panels unless they care about some information. If you
+ still need the panel just call `nk_window_get_panel`.
+- 2016/10/21 (1.160)- Changed widget border drawing to stroked rectangle from filled
+ rectangle for less overdraw and widget background transparency.
+- 2016/10/18 (1.160)- Added `nk_edit_focus` for manually edit widget focus control
+- 2016/09/29 (1.157)- Fixed deduction of basic type in non `<stdint.h>` compilation
+- 2016/09/29 (1.156)- Fixed edit widget UTF-8 text cursor drawing bug
+- 2016/09/28 (1.156)- Fixed edit widget UTF-8 text appending/inserting/removing
+- 2016/09/28 (1.156)- Fixed drawing bug inside edit widgets which offset all text
+ text in every edit widget if one of them is scrolled.
+- 2016/09/28 (1.155)- Fixed small bug in edit widgets if not active. The wrong
+ text length is passed. It should have been in bytes but
+ was passed as glyphes.
+- 2016/09/20 (1.154)- Fixed color button size calculation
+- 2016/09/20 (1.153)- Fixed some `nk_vsnprintf` behavior bugs and removed
+ `<stdio.h>` again from `NK_INCLUDE_STANDARD_VARARGS`.
+- 2016/09/18 (1.152)- C89 does not support vsnprintf only C99 and newer as well
+ as C++11 and newer. In addition to use vsnprintf you have
+ to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`
+ is not enough. That behavior is now fixed. By default if
+ both varargs as well as stdio is selected I try to use
+ vsnprintf if not possible I will revert to vsprintf. If
+ varargs but not stdio was defined I will use my own function.
+- 2016/09/15 (1.151)- Fixed panel `close` behavior for deeper panel levels
+- 2016/09/15 (1.151)- Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`
+- 2016/09/13 (1.15) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,
+ and contextual which prevented closing in y-direction if
+ popup did not reach max height.
+ In addition the height parameter was changed into vec2
+ for width and height to have more control over the popup size.
+- 2016/09/13 (1.15) - Cleaned up and extended type selection
+- 2016/09/13 (1.141)- Fixed slider behavior hopefully for the last time. This time
+ all calculation are correct so no more hackery.
+- 2016/09/13 (1.141)- Internal change to divide window/panel flags into panel flags and types.
+ Suprisinly spend years in C and still happened to confuse types
+ with flags. Probably something to take note.
+- 2016/09/08 (1.14)- Added additional helper function to make it easier to just
+ take the produced buffers from `nk_convert` and unplug the
+ iteration process from `nk_context`. So now you can
+ just use the vertex,element and command buffer + two pointer
+ inside the command buffer retrieved by calls `nk__draw_begin`
+ and `nk__draw_end` and macro `nk_draw_foreach_bounded`.
+- 2016/09/08 (1.14)- Added additional asserts to make sure every `nk_xxx_begin` call
+ for windows, popups, combobox, menu and contextual is guarded by
+ `if` condition and does not produce false drawing output.
+- 2016/09/08 (1.14)- Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`
+ to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and
+ `NK_SYMBOL_RECT_OUTLINE`.
+- 2016/09/08 (1.14)- Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`
+ to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and
+ `NK_SYMBOL_CIRCLE_OUTLINE`.
+- 2016/09/08 (1.14)- Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`
+ is not defined by supporting the biggest compiler GCC, clang and MSVC.
+- 2016/09/07 (1.133)- Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error
+- 2016/09/04 (1.132)- Fixed wrong combobox height calculation
+- 2016/09/03 (1.131)- Fixed gaps inside combo boxes in OpenGL
+- 2016/09/02 (1.13) - Changed nuklear to not have any default vertex layout and
+ instead made it user provided. The range of types to convert
+ to is quite limited at the moment, but I would be more than
+ happy to accept PRs to add additional.
+- 2016/08/30 (1.12) - Removed unused variables
+- 2016/08/30 (1.12) - Fixed C++ build errors
+- 2016/08/30 (1.12) - Removed mouse dragging from SDL demo since it does not work correctly
+- 2016/08/30 (1.12) - Tweaked some default styling variables
+- 2016/08/30 (1.12) - Hopefully fixed drawing bug in slider, in general I would
+ refrain from using slider with a big number of steps.
+- 2016/08/30 (1.12) - Fixed close and minimize button which would fire even if the
+ window was in Read Only Mode.
+- 2016/08/30 (1.12) - Fixed popup panel padding handling which was previously just
+ a hack for combo box and menu.
+- 2016/08/30 (1.12) - Removed `NK_WINDOW_DYNAMIC` flag from public API since
+ it is bugged and causes issues in window selection.
+- 2016/08/30 (1.12) - Removed scaler size. The size of the scaler is now
+ determined by the scrollbar size
+- 2016/08/30 (1.12) - Fixed some drawing bugs caused by changes from 1.11
+- 2016/08/30 (1.12) - Fixed overlapping minimized window selection
+- 2016/08/30 (1.11) - Removed some internal complexity and overly complex code
+ handling panel padding and panel border.
+- 2016/08/29 (1.10) - Added additional height parameter to `nk_combobox_xxx`
+- 2016/08/29 (1.10) - Fixed drawing bug in dynamic popups
+- 2016/08/29 (1.10) - Added experimental mouse scrolling to popups, menus and comboboxes
+- 2016/08/26 (1.10) - Added window name string prepresentation to account for
+ hash collisions. Currently limited to NK_WINDOW_MAX_NAME
+ which in term can be redefined if not big enough.
+- 2016/08/26 (1.10) - Added stacks for temporary style/UI changes in code
+- 2016/08/25 (1.10) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'
+ to account for key press and release happening in one frame.
+- 2016/08/25 (1.10) - Added additional nk_edit flag to directly jump to the end on activate
+- 2016/08/17 (1.096)- Removed invalid check for value zero in nk_propertyx
+- 2016/08/16 (1.095)- Fixed ROM mode for deeper levels of popup windows parents.
+- 2016/08/15 (1.094)- Editbox are now still active if enter was pressed with flag
+ `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep
+ typing after commiting.
+- 2016/08/15 (1.094)- Removed redundant code
+- 2016/08/15 (1.094)- Fixed negative numbers in `nk_strtoi` and remove unused variable
+- 2016/08/15 (1.093)- Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background
+ window only as selected by hovering and not by clicking.
+- 2016/08/14 (1.092)- Fixed a bug in font atlas which caused wrong loading
+ of glyphes for font with multiple ranges.
+- 2016/08/12 (1.091)- Added additional function to check if window is currently
+ hidden and therefore not visible.
+- 2016/08/12 (1.091)- nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`
+ instead of the old flag `NK_WINDOW_HIDDEN`
+- 2016/08/09 (1.09) - Added additional double version to nk_property and changed
+ the underlying implementation to not cast to float and instead
+ work directly on the given values.
+- 2016/08/09 (1.08) - Added additional define to overwrite library internal
+ floating pointer number to string conversion for additional
+ precision.
+- 2016/08/09 (1.08) - Added additional define to overwrite library internal
+ string to floating point number conversion for additional
+ precision.
+- 2016/08/08 (1.072)- Fixed compiling error without define NK_INCLUDE_FIXED_TYPE
+- 2016/08/08 (1.071)- Fixed possible floating point error inside `nk_widget` leading
+ to wrong wiget width calculation which results in widgets falsly
+ becomming tagged as not inside window and cannot be accessed.
+- 2016/08/08 (1.07) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and
+ closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown
+ by using `nk_window_show` and closed by either clicking the close
+ icon in a window or by calling `nk_window_close`. Only closed
+ windows get removed at the end of the frame while hidden windows
+ remain.
+- 2016/08/08 (1.06) - Added `nk_edit_string_zero_terminated` as a second option to
+ `nk_edit_string` which takes, edits and outputs a '\0' terminated string.
+- 2016/08/08 (1.054)- Fixed scrollbar auto hiding behavior
+- 2016/08/08 (1.053)- Fixed wrong panel padding selection in `nk_layout_widget_space`
+- 2016/08/07 (1.052)- Fixed old bug in dynamic immediate mode layout API, calculating
+ wrong item spacing and panel width.
+- 2016/08/07 (1.051)- Hopefully finally fixed combobox popup drawing bug
+- 2016/08/07 (1.05) - Split varargs away from NK_INCLUDE_STANDARD_IO into own
+ define NK_INCLUDE_STANDARD_VARARGS to allow more fine
+ grained controlled over library includes.
+- 2016/08/06 (1.045)- Changed memset calls to NK_MEMSET
+- 2016/08/04 (1.044)- Fixed fast window scaling behavior
+- 2016/08/04 (1.043)- Fixed window scaling, movement bug which appears if you
+ move/scale a window and another window is behind it.
+ If you are fast enough then the window behind gets activated
+ and the operation is blocked. I now require activating
+ by hovering only if mouse is not pressed.
+- 2016/08/04 (1.042)- Fixed changing fonts
+- 2016/08/03 (1.041)- Fixed `NK_WINDOW_BACKGROUND` behavior
+- 2016/08/03 (1.04) - Added color parameter to `nk_draw_image`
+- 2016/08/03 (1.04) - Added additional window padding style attributes for
+ sub windows (combo, menu, ...)
+- 2016/08/03 (1.04) - Added functions to show/hide software cursor
+- 2016/08/03 (1.04) - Added `NK_WINDOW_BACKGROUND` flag to force a window
+ to be always in the background of the screen
+- 2016/08/03 (1.032)- Removed invalid assert macro for NK_RGB color picker
+- 2016/08/01 (1.031)- Added helper macros into header include guard
+- 2016/07/29 (1.03) - Moved the window/table pool into the header part to
+ simplify memory management by removing the need to
+ allocate the pool.
+- 2016/07/29 (1.03) - Added auto scrollbar hiding window flag which if enabled
+ will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT
+ seconds without window interaction. To make it work
+ you have to also set a delta time inside the `nk_context`.
+- 2016/07/25 (1.02) - Fixed small panel and panel border drawing bugs
+- 2016/07/15 (1.01) - Added software cursor to `nk_style` and `nk_context`
+- 2016/07/15 (1.01) - Added const correctness to `nk_buffer_push' data argument
+- 2016/07/15 (1.01) - Removed internal font baking API and simplified
+ font atlas memory management by converting pointer
+ arrays for fonts and font configurations to lists.
+- 2016/07/15 (1.01) - Changed button API to use context dependend button
+ behavior instead of passing it for every function call.
+
diff --git a/nuklear/Readme.md b/nuklear/Readme.md
new file mode 100644
index 0000000..29d56d3
--- /dev/null
+++ b/nuklear/Readme.md
@@ -0,0 +1,111 @@
+[![Build Status](https://travis-ci.org/vurtun/nuklear.svg)](https://travis-ci.org/vurtun/nuklear)
+
+# Nuklear
+This is a minimal state immediate mode graphical user interface toolkit
+written in ANSI C and licensed under public domain. It was designed as a simple
+embeddable user interface for application and does not have any dependencies,
+a default renderbackend or OS window and input handling but instead provides a very modular
+library approach by using simple input state for input and draw
+commands describing primitive shapes as output. So instead of providing a
+layered library that tries to abstract over a number of platform and
+render backends it only focuses on the actual UI.
+
+## Features
+- Immediate mode graphical user interface toolkit
+- Single header library
+- Written in C89 (ANSI C)
+- Small codebase (~15kLOC)
+- Focus on portability, efficiency and simplicity
+- No dependencies (not even the standard library if not wanted)
+- Fully skinnable and customizable
+- Low memory footprint with total memory control if needed or wanted
+- UTF-8 support
+- No global or hidden state
+- Customizable library modules (you can compile and use only what you need)
+- Optional font baker and vertex buffer output
+
+## Building
+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 `#include`ing this file, e.g.:
+```c
+#define NK_IMPLEMENTATION
+#include "nuklear.h"
+```
+IMPORTANT: Every time you include "nuklear.h" you have to define the same optional flags.
+This is very important not doing it either leads to compiler errors or even worse stack corruptions.
+
+## Gallery
+![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
+![screen](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)
+![screen2](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)
+![node](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)
+![skinning](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)
+![gamepad](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)
+
+## Example
+```c
+/* init gui state */
+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;
+
+if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
+ /* fixed widget pixel width */
+ nk_layout_row_static(&ctx, 30, 80, 1);
+ if (nk_button_label(&ctx, "button")) {
+ /* event handling */
+ }
+
+ /* fixed widget window ratio width */
+ nk_layout_row_dynamic(&ctx, 30, 2);
+ if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
+
+ /* custom widget pixel width */
+ nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
+ {
+ nk_layout_row_push(&ctx, 50);
+ nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
+ nk_layout_row_push(&ctx, 110);
+ nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
+ }
+ nk_layout_row_end(&ctx);
+}
+nk_end(&ctx);
+```
+![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
+
+## Bindings:
+Java: https://github.com/glegris/nuklear4j
+Golang: https://github.com/golang-ui/nuklear
+Rust: https://github.com/snuk182/nuklear-rust
+
+## 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](https://github.com/ocornut/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](https://github.com/nothings/stb) which restored my 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.
+
diff --git a/nuklear/demo/calculator.c b/nuklear/demo/calculator.c
new file mode 100644
index 0000000..b871301
--- /dev/null
+++ b/nuklear/demo/calculator.c
@@ -0,0 +1,64 @@
+/* nuklear - v1.00 - public domain */
+static void
+calculator(struct nk_context *ctx)
+{
+ if (nk_begin(ctx, "Calculator", nk_rect(10, 10, 180, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
+ {
+ static int set = 0, prev = 0, op = 0;
+ static const char numbers[] = "789456123";
+ static const char ops[] = "+-*/";
+ static double a = 0, b = 0;
+ static double *current = &a;
+
+ size_t i = 0;
+ int solve = 0;
+ {int len; char buffer[256];
+ nk_layout_row_dynamic(ctx, 35, 1);
+ len = snprintf(buffer, 256, "%.2f", *current);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_float);
+ buffer[len] = 0;
+ *current = atof(buffer);}
+
+ nk_layout_row_dynamic(ctx, 35, 4);
+ for (i = 0; i < 16; ++i) {
+ if (i >= 12 && i < 15) {
+ if (i > 12) continue;
+ if (nk_button_label(ctx, "C")) {
+ a = b = op = 0; current = &a; set = 0;
+ } if (nk_button_label(ctx, "0")) {
+ *current = *current*10.0f; set = 0;
+ } if (nk_button_label(ctx, "=")) {
+ solve = 1; prev = op; op = 0;
+ }
+ } else if (((i+1) % 4)) {
+ if (nk_button_text(ctx, &numbers[(i/4)*3+i%4], 1)) {
+ *current = *current * 10.0f + numbers[(i/4)*3+i%4] - '0';
+ set = 0;
+ }
+ } else if (nk_button_text(ctx, &ops[i/4], 1)) {
+ if (!set) {
+ if (current != &b) {
+ current = &b;
+ } else {
+ prev = op;
+ solve = 1;
+ }
+ }
+ op = ops[i/4];
+ set = 1;
+ }
+ }
+ if (solve) {
+ if (prev == '+') a = a + b;
+ if (prev == '-') a = a - b;
+ if (prev == '*') a = a * b;
+ if (prev == '/') a = a / b;
+ current = &a;
+ if (set) current = &b;
+ b = 0; set = 0;
+ }
+ }
+ nk_end(ctx);
+}
+
diff --git a/nuklear/demo/d3d11/build.bat b/nuklear/demo/d3d11/build.bat
new file mode 100644
index 0000000..31bd0e0
--- /dev/null
+++ b/nuklear/demo/d3d11/build.bat
@@ -0,0 +1,9 @@
+@echo off
+
+rem This will use VS2015 for compiler
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+fxc.exe /nologo /T vs_4_0_level_9_0 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d11_vertex_shader.h /Vn nk_d3d11_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl
+fxc.exe /nologo /T ps_4_0_level_9_0 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d11_pixel_shader.h /Vn nk_d3d11_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl
+
+cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib d3d11.lib /link /incremental:no
diff --git a/nuklear/demo/d3d11/main.c b/nuklear/demo/d3d11/main.c
new file mode 100644
index 0000000..bc0dc64
--- /dev/null
+++ b/nuklear/demo/d3d11/main.c
@@ -0,0 +1,278 @@
+/* nuklear - v1.17 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d11.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_INDEX_BUFFER 128 * 1024
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D11_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d11.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #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])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static IDXGISwapChain *swap_chain;
+static ID3D11Device *device;
+static ID3D11DeviceContext *context;
+static ID3D11RenderTargetView* rt_view;
+
+static void
+set_swap_chain_size(int width, int height)
+{
+ ID3D11Texture2D *back_buffer;
+ D3D11_RENDER_TARGET_VIEW_DESC desc;
+ HRESULT hr;
+
+ if (rt_view)
+ ID3D11RenderTargetView_Release(rt_view);
+
+ ID3D11DeviceContext_OMSetRenderTargets(context, 0, NULL, NULL);
+
+ hr = IDXGISwapChain_ResizeBuffers(swap_chain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
+ {
+ /* to recover from this, you'll need to recreate device and all the resources */
+ MessageBoxW(NULL, L"DXGI device is removed or reset!", L"Error", 0);
+ exit(0);
+ }
+ assert(SUCCEEDED(hr));
+
+ memset(&desc, 0, sizeof(desc));
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+
+ hr = IDXGISwapChain_GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, &back_buffer);
+ assert(SUCCEEDED(hr));
+
+ hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)back_buffer, &desc, &rt_view);
+ assert(SUCCEEDED(hr));
+
+ ID3D11Texture2D_Release(back_buffer);
+}
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_SIZE:
+ if (swap_chain)
+ {
+ int width = LOWORD(lparam);
+ int height = HIWORD(lparam);
+ set_swap_chain_size(width, height);
+ nk_d3d11_resize(context, width, height);
+ }
+ break;
+ }
+
+ if (nk_d3d11_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ WNDCLASSW wc;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ int running = 1;
+ HRESULT hr;
+ D3D_FEATURE_LEVEL feature_level;
+ DXGI_SWAP_CHAIN_DESC swap_chain_desc;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+
+ /* D3D11 setup */
+ memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
+ swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
+ swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
+ swap_chain_desc.SampleDesc.Count = 1;
+ swap_chain_desc.SampleDesc.Quality = 0;
+ swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swap_chain_desc.BufferCount = 1;
+ swap_chain_desc.OutputWindow = wnd;
+ swap_chain_desc.Windowed = TRUE;
+ swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ swap_chain_desc.Flags = 0;
+ if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE,
+ NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,
+ &swap_chain, &device, &feature_level, &context)))
+ {
+ /* if hardware device fails, then try WARP high-performance
+ software rasterizer, this is useful for RDP sessions */
+ hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP,
+ NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,
+ &swap_chain, &device, &feature_level, &context);
+ assert(SUCCEEDED(hr));
+ }
+ set_swap_chain_size(WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ /* GUI */
+ ctx = nk_d3d11_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_d3d11_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_d3d11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 22, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ {/* Draw */
+ float bg[4];
+ nk_color_fv(bg, background);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rt_view, bg);
+ ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rt_view, NULL);
+ nk_d3d11_render(context, NK_ANTI_ALIASING_ON);
+ hr = IDXGISwapChain_Present(swap_chain, 1, 0);
+ if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {
+ /* to recover from this, you'll need to recreate device and all the resources */
+ MessageBoxW(NULL, L"D3D11 device is lost or removed!", L"Error", 0);
+ break;
+ } else if (hr == DXGI_STATUS_OCCLUDED) {
+ /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+ Sleep(10);
+ }
+ assert(SUCCEEDED(hr));}
+ }
+
+ ID3D11DeviceContext_ClearState(context);
+ nk_d3d11_shutdown();
+ ID3D11ShaderResourceView_Release(rt_view);
+ ID3D11DeviceContext_Release(context);
+ ID3D11Device_Release(device);
+ IDXGISwapChain_Release(swap_chain);
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
diff --git a/nuklear/demo/d3d11/nuklear_d3d11.h b/nuklear/demo/d3d11/nuklear_d3d11.h
new file mode 100644
index 0000000..efddf0d
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11.h
@@ -0,0 +1,617 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D11_H_
+#define NK_D3D11_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct ID3D11Device ID3D11Device;
+typedef struct ID3D11DeviceContext ID3D11DeviceContext;
+
+NK_API struct nk_context *nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer);
+NK_API void nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_d3d11_font_stash_end(void);
+NK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing);
+NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);
+NK_API void nk_d3d11_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D11_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d11.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <float.h>
+#include <assert.h>
+
+#include "nuklear_d3d11_vertex_shader.h"
+#include "nuklear_d3d11_pixel_shader.h"
+
+struct nk_d3d11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct
+{
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_buffer cmds;
+
+ struct nk_draw_null_texture null;
+ unsigned int max_vertex_buffer;
+ unsigned int max_index_buffer;
+
+ D3D11_VIEWPORT viewport;
+ ID3D11Device *device;
+ ID3D11RasterizerState *rasterizer_state;
+ ID3D11VertexShader *vertex_shader;
+ ID3D11InputLayout *input_layout;
+ ID3D11Buffer *const_buffer;
+ ID3D11PixelShader *pixel_shader;
+ ID3D11BlendState *blend_state;
+ ID3D11Buffer *index_buffer;
+ ID3D11Buffer *vertex_buffer;
+ ID3D11ShaderResourceView *font_texture_view;
+ ID3D11SamplerState *sampler_state;
+} d3d11;
+
+NK_API void
+nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing AA)
+{
+ const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ const UINT stride = sizeof(struct nk_d3d11_vertex);
+ const UINT offset = 0;
+
+ ID3D11DeviceContext_IASetInputLayout(context, d3d11.input_layout);
+ ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &d3d11.vertex_buffer, &stride, &offset);
+ ID3D11DeviceContext_IASetIndexBuffer(context, d3d11.index_buffer, DXGI_FORMAT_R16_UINT, 0);
+ ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+ ID3D11DeviceContext_VSSetShader(context, d3d11.vertex_shader, NULL, 0);
+ ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &d3d11.const_buffer);
+
+ ID3D11DeviceContext_PSSetShader(context, d3d11.pixel_shader, NULL, 0);
+ ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &d3d11.sampler_state);
+
+ ID3D11DeviceContext_OMSetBlendState(context, d3d11.blend_state, blend_factor, 0xffffffff);
+ ID3D11DeviceContext_RSSetState(context, d3d11.rasterizer_state);
+ ID3D11DeviceContext_RSSetViewports(context, 1, &d3d11.viewport);
+
+ /* Convert from command queue into draw list and draw to screen */
+ {/* load draw vertices & elements directly into vertex + element buffer */
+ D3D11_MAPPED_SUBRESOURCE vertices;
+ D3D11_MAPPED_SUBRESOURCE indices;
+ const struct nk_draw_command *cmd;
+ UINT offset = 0;
+ HRESULT hr;
+
+ hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertices);
+ NK_ASSERT(SUCCEEDED(hr));
+ hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ {/* fill converting configuration */
+ struct nk_convert_config config;
+ NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ memset(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_d3d11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_d3d11_vertex);
+ 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 = d3d11.null;
+
+ {/* setup buffers to load vertices and elements */
+ struct nk_buffer vbuf, ibuf;
+ nk_buffer_init_fixed(&vbuf, vertices.pData, (size_t)d3d11.max_vertex_buffer);
+ nk_buffer_init_fixed(&ibuf, indices.pData, (size_t)d3d11.max_index_buffer);
+ nk_convert(&d3d11.ctx, &d3d11.cmds, &vbuf, &ibuf, &config);}
+ }
+
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.vertex_buffer, 0);
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.index_buffer, 0);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, &d3d11.ctx, &d3d11.cmds)
+ {
+ D3D11_RECT scissor;
+ ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;
+ if (!cmd->elem_count) continue;
+
+ scissor.left = (LONG)cmd->clip_rect.x;
+ scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
+ scissor.top = (LONG)cmd->clip_rect.y;
+ scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
+
+ ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &texture_view);
+ ID3D11DeviceContext_RSSetScissorRects(context, 1, &scissor);
+ ID3D11DeviceContext_DrawIndexed(context, (UINT)cmd->elem_count, offset, 0);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&d3d11.ctx);}
+}
+
+static void
+nk_d3d11_get_projection_matrix(int width, int height, float *result)
+{
+ const float L = 0.0f;
+ const float R = (float)width;
+ const float T = 0.0f;
+ const float B = (float)height;
+ float matrix[4][4] =
+ {
+ { 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
+ };
+ memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height)
+{
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ if (SUCCEEDED(ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)))
+ {
+ nk_d3d11_get_projection_matrix(width, height, (float *)mapped.pData);
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.const_buffer, 0);
+
+ d3d11.viewport.Width = (float)width;
+ d3d11.viewport.Height = (float)height;
+ }
+}
+
+NK_API int
+nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&d3d11.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&d3d11.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&d3d11.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&d3d11.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&d3d11.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&d3d11.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&d3d11.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&d3d11.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&d3d11.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+nk_d3d11_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ (void)usr;
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ {
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem)
+ {
+ SIZE_T size = GlobalSize(mem) - 1;
+ if (size)
+ {
+ LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+ if (wstr)
+ {
+ int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
+ if (utf8size)
+ {
+ char* utf8 = (char*)malloc(utf8size);
+ if (utf8)
+ {
+ WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ }
+ }
+ GlobalUnlock(mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+static void
+nk_d3d11_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ (void)usr;
+ if (OpenClipboard(NULL))
+ {
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (wsize)
+ {
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (mem)
+ {
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (wstr)
+ {
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+ SetClipboardData(CF_UNICODETEXT, mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+NK_API struct nk_context*
+nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer)
+{
+ HRESULT hr;
+ d3d11.max_vertex_buffer = max_vertex_buffer;
+ d3d11.max_index_buffer = max_index_buffer;
+ d3d11.device = device;
+ ID3D11Device_AddRef(device);
+
+ nk_init_default(&d3d11.ctx, 0);
+ d3d11.ctx.clip.copy = nk_d3d11_clipbard_copy;
+ d3d11.ctx.clip.paste = nk_d3d11_clipbard_paste;
+ d3d11.ctx.clip.userdata = nk_handle_ptr(0);
+
+ nk_buffer_init_default(&d3d11.cmds);
+
+ {/* rasterizer state */
+ D3D11_RASTERIZER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.FrontCounterClockwise = FALSE;
+ desc.DepthBias = 0;
+ desc.DepthBiasClamp = 0;
+ desc.SlopeScaledDepthBias = 0.0f;
+ desc.DepthClipEnable = TRUE;
+ desc.ScissorEnable = TRUE;
+ desc.MultisampleEnable = FALSE;
+ desc.AntialiasedLineEnable = FALSE;
+ hr = ID3D11Device_CreateRasterizerState(device,&desc, &d3d11.rasterizer_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* vertex shader */
+ {hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* input layout */
+ {const D3D11_INPUT_ELEMENT_DESC layout[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(struct nk_d3d11_vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ hr = ID3D11Device_CreateInputLayout(device,layout, ARRAYSIZE(layout), nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), &d3d11.input_layout);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* constant buffer */
+ {float matrix[4*4];
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.ByteWidth = sizeof(matrix);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+
+ {D3D11_SUBRESOURCE_DATA data;
+ data.pSysMem = matrix;
+ data.SysMemPitch = 0;
+ data.SysMemSlicePitch = 0;
+
+ nk_d3d11_get_projection_matrix(width, height, matrix);
+ hr = ID3D11Device_CreateBuffer(device, &desc, &data, &d3d11.const_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}}
+
+ /* pixel shader */
+ {hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ {/* blend state */
+ D3D11_BLEND_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.AlphaToCoverageEnable = FALSE;
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ hr = ID3D11Device_CreateBlendState(device, &desc, &d3d11.blend_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* vertex buffer */
+ {D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = max_vertex_buffer;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.vertex_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* index buffer */
+ {D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = max_index_buffer;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.index_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* sampler state */
+ {D3D11_SAMPLER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.MipLODBias = 0.0f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.0f;
+ desc.MaxLOD = FLT_MAX;
+ hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11.sampler_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* viewport */
+ {d3d11.viewport.TopLeftX = 0.0f;
+ d3d11.viewport.TopLeftY = 0.0f;
+ d3d11.viewport.Width = (float)width;
+ d3d11.viewport.Height = (float)height;
+ d3d11.viewport.MinDepth = 0.0f;
+ d3d11.viewport.MaxDepth = 1.0f;}
+ return &d3d11.ctx;
+}
+
+NK_API void
+nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&d3d11.atlas);
+ nk_font_atlas_begin(&d3d11.atlas);
+ *atlas = &d3d11.atlas;
+}
+
+NK_API void
+nk_d3d11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&d3d11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+
+ /* upload font to texture and create texture view */
+ {ID3D11Texture2D *font_texture;
+ HRESULT hr;
+
+ D3D11_TEXTURE2D_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Width = (UINT)w;
+ desc.Height = (UINT)h;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ {D3D11_SUBRESOURCE_DATA data;
+ data.pSysMem = image;
+ data.SysMemPitch = (UINT)(w * 4);
+ data.SysMemSlicePitch = 0;
+ hr = ID3D11Device_CreateTexture2D(d3d11.device, &desc, &data, &font_texture);
+ assert(SUCCEEDED(hr));}
+
+ {D3D11_SHADER_RESOURCE_VIEW_DESC srv;
+ memset(&srv, 0, sizeof(srv));
+ srv.Format = desc.Format;
+ srv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv.Texture2D.MipLevels = 1;
+ srv.Texture2D.MostDetailedMip = 0;
+ hr = ID3D11Device_CreateShaderResourceView(d3d11.device, (ID3D11Resource *)font_texture, &srv, &d3d11.font_texture_view);
+ assert(SUCCEEDED(hr));}
+ ID3D11Texture2D_Release(font_texture);}
+
+ nk_font_atlas_end(&d3d11.atlas, nk_handle_ptr(d3d11.font_texture_view), &d3d11.null);
+ if (d3d11.atlas.default_font)
+ nk_style_set_font(&d3d11.ctx, &d3d11.atlas.default_font->handle);
+}
+
+NK_API
+void nk_d3d11_shutdown(void)
+{
+ nk_font_atlas_clear(&d3d11.atlas);
+ nk_buffer_free(&d3d11.cmds);
+ nk_free(&d3d11.ctx);
+
+ ID3D11SamplerState_Release(d3d11.sampler_state);
+ ID3D11ShaderResourceView_Release(d3d11.font_texture_view);
+ ID3D11Buffer_Release(d3d11.vertex_buffer);
+ ID3D11Buffer_Release(d3d11.index_buffer);
+ ID3D11BlendState_Release(d3d11.blend_state);
+ ID3D11PixelShader_Release(d3d11.pixel_shader);
+ ID3D11Buffer_Release(d3d11.const_buffer);
+ ID3D11VertexShader_Release(d3d11.vertex_shader);
+ ID3D11InputLayout_Release(d3d11.input_layout);
+ ID3D11RasterizerState_Release(d3d11.rasterizer_state);
+ ID3D11Device_Release(d3d11.device);
+}
+
+#endif
+
diff --git a/nuklear/demo/d3d11/nuklear_d3d11.hlsl b/nuklear/demo/d3d11/nuklear_d3d11.hlsl
new file mode 100644
index 0000000..a932dca
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11.hlsl
@@ -0,0 +1,36 @@
+//
+cbuffer buffer0 : register(b0)
+{
+ float4x4 ProjectionMatrix;
+};
+
+sampler sampler0 : register(s0);
+Texture2D<float4> texture0 : register(t0);
+
+struct VS_INPUT
+{
+ float2 pos : POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+struct PS_INPUT
+{
+ float4 pos : SV_POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+PS_INPUT vs(VS_INPUT input)
+{
+ PS_INPUT output;
+ output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
+ output.col = input.col;
+ output.uv = input.uv;
+ return output;
+}
+
+float4 ps(PS_INPUT input) : SV_Target
+{
+ return input.col * texture0.Sample(sampler0, input.uv);
+}
diff --git a/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h b/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h
new file mode 100644
index 0000000..1447559
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h
@@ -0,0 +1,179 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION 0 xyzw 0 POS float
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target 0 xyzw 0 TARGET float xyzw
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler Source Resource
+// -------------- --------------- ----------------
+// s0 s0 t0
+//
+//
+// Level9 shader bytecode:
+//
+ ps_2_0
+ dcl t0
+ dcl t1.xy
+ dcl_2d s0
+ texld r0, t1, s0
+ mul r0, r0, t0
+ mov oC0, r0
+
+// approximately 3 instruction slots used (1 texture, 2 arithmetic)
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler Source Resource
+// -------------- --------------- ----------------
+// s0 s0 t0
+//
+//
+// XNA shader bytecode:
+//
+ ps_2_0
+ dcl t0
+ dcl t1.xy
+ dcl_2d s0
+ texld r0, r2, s0
+ mul oC0, r0, r1
+
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xyzw
+dcl_input_ps linear v2.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v2.xyxx, t0.xyzw, s0
+mul o0.xyzw, r0.xyzw, v1.xyzw
+ret
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d11_pixel_shader[] =
+{
+ 68, 88, 66, 67, 249, 46,
+ 26, 75, 111, 182, 161, 241,
+ 199, 179, 191, 89, 44, 229,
+ 245, 103, 1, 0, 0, 0,
+ 124, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 176, 0, 0, 0, 56, 1,
+ 0, 0, 212, 1, 0, 0,
+ 72, 2, 0, 0, 88, 78,
+ 65, 83, 116, 0, 0, 0,
+ 116, 0, 0, 0, 0, 2,
+ 255, 255, 76, 0, 0, 0,
+ 40, 0, 0, 0, 0, 0,
+ 40, 0, 0, 0, 40, 0,
+ 0, 0, 40, 0, 1, 0,
+ 36, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 0, 2,
+ 255, 255, 31, 0, 0, 2,
+ 0, 0, 0, 128, 0, 0,
+ 15, 176, 31, 0, 0, 2,
+ 0, 0, 0, 128, 1, 0,
+ 3, 176, 31, 0, 0, 2,
+ 0, 0, 0, 144, 0, 8,
+ 15, 160, 66, 0, 0, 3,
+ 0, 0, 15, 128, 2, 0,
+ 228, 128, 0, 8, 228, 160,
+ 5, 0, 0, 3, 0, 8,
+ 15, 128, 0, 0, 228, 128,
+ 1, 0, 228, 128, 255, 255,
+ 0, 0, 65, 111, 110, 57,
+ 128, 0, 0, 0, 128, 0,
+ 0, 0, 0, 2, 255, 255,
+ 88, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 40, 0,
+ 0, 0, 40, 0, 0, 0,
+ 40, 0, 1, 0, 36, 0,
+ 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 2, 255, 255,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 0, 0, 15, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 1, 0, 3, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 144, 0, 8, 15, 160,
+ 66, 0, 0, 3, 0, 0,
+ 15, 128, 1, 0, 228, 176,
+ 0, 8, 228, 160, 5, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 228, 128, 0, 0,
+ 228, 176, 1, 0, 0, 2,
+ 0, 8, 15, 128, 0, 0,
+ 228, 128, 255, 255, 0, 0,
+ 83, 72, 68, 82, 148, 0,
+ 0, 0, 64, 0, 0, 0,
+ 37, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 0, 4, 0, 112, 16, 0,
+ 0, 0, 0, 0, 85, 85,
+ 0, 0, 98, 16, 0, 3,
+ 242, 16, 16, 0, 1, 0,
+ 0, 0, 98, 16, 0, 3,
+ 50, 16, 16, 0, 2, 0,
+ 0, 0, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 69, 0,
+ 0, 9, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 16,
+ 16, 0, 2, 0, 0, 0,
+ 70, 126, 16, 0, 0, 0,
+ 0, 0, 0, 96, 16, 0,
+ 0, 0, 0, 0, 56, 0,
+ 0, 7, 242, 32, 16, 0,
+ 0, 0, 0, 0, 70, 14,
+ 16, 0, 0, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 62, 0, 0, 1,
+ 73, 83, 71, 78, 108, 0,
+ 0, 0, 3, 0, 0, 0,
+ 8, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 15, 15, 0, 0, 98, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 0, 0, 0,
+ 3, 3, 0, 0, 83, 86,
+ 95, 80, 79, 83, 73, 84,
+ 73, 79, 78, 0, 67, 79,
+ 76, 79, 82, 0, 84, 69,
+ 88, 67, 79, 79, 82, 68,
+ 0, 171, 79, 83, 71, 78,
+ 44, 0, 0, 0, 1, 0,
+ 0, 0, 8, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 83, 86, 95, 84, 97, 114,
+ 103, 101, 116, 0, 171, 171
+};
diff --git a/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h b/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h
new file mode 100644
index 0000000..770d2dd
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h
@@ -0,0 +1,350 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION 0 xy 0 NONE float xy
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION 0 xyzw 0 POS float xyzw
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c1 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg Constant Description
+// ---------- --------------------------------------------------
+// c0 Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+ vs_2_0
+ def c5, 0, 1, 0, 0
+ dcl_texcoord v0
+ dcl_texcoord1 v1
+ dcl_texcoord2 v2
+ mul r0, v0.x, c1
+ mad r0, c2, v0.y, r0
+ mov r1.xy, c5
+ mad r0, c3, r1.x, r0
+ mad r0, c4, r1.y, r0
+ mul r1.xy, r0.w, c0
+ add oPos.xy, r0, r1
+ mov oPos.zw, r0
+ mov oT0, v1
+ mov oT1.xy, v2
+
+// approximately 10 instruction slots used
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// XNA Prepass shader bytecode:
+//
+ vs_2_0
+ def c4, 0, 1, 0, 0
+ dcl_texcoord v0
+ mul r1, r0.x, c0
+ mad r0, c1, r0.y, r1
+ mov r1.xy, c4
+ mad r0, c2, r1.x, r0
+ mad r0, c3, r1.y, r0
+ mov oPos, r0
+
+// approximately 6 instruction slots used
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// XNA shader bytecode:
+//
+ vs_2_0
+ def c4, 0, 1, 0, 0
+ dcl_texcoord v0
+ dcl_texcoord1 v1
+ dcl_texcoord2 v2
+ mov oT0, r1
+ mov oT1.xy, r2
+ mul r1, r0.x, c0
+ mad r0, c1, r0.y, r1
+ mov r1.xy, c4
+ mad r0, c2, r1.x, r0
+ mad r0, c3, r1.y, r0
+ mov oPos, r0
+
+// approximately 8 instruction slots used
+vs_4_0
+dcl_constantbuffer cb0[4], immediateIndexed
+dcl_input v0.xy
+dcl_input v1.xyzw
+dcl_input v2.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xyzw
+dcl_output o2.xy
+dcl_temps 1
+mul r0.xyzw, v0.xxxx, cb0[0].xyzw
+mad r0.xyzw, cb0[1].xyzw, v0.yyyy, r0.xyzw
+mad r0.xyzw, cb0[2].xyzw, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzw
+mad o0.xyzw, cb0[3].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000), r0.xyzw
+mov o1.xyzw, v1.xyzw
+mov o2.xy, v2.xyxx
+ret
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d11_vertex_shader[] =
+{
+ 68, 88, 66, 67, 215, 245,
+ 86, 155, 188, 117, 37, 118,
+ 193, 207, 209, 90, 160, 153,
+ 246, 188, 1, 0, 0, 0,
+ 72, 5, 0, 0, 6, 0,
+ 0, 0, 56, 0, 0, 0,
+ 48, 1, 0, 0, 248, 1,
+ 0, 0, 20, 3, 0, 0,
+ 100, 4, 0, 0, 212, 4,
+ 0, 0, 88, 78, 65, 83,
+ 240, 0, 0, 0, 240, 0,
+ 0, 0, 0, 2, 254, 255,
+ 192, 0, 0, 0, 48, 0,
+ 0, 0, 1, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 48, 0, 0, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2,
+ 254, 255, 81, 0, 0, 5,
+ 4, 0, 15, 160, 0, 0,
+ 0, 0, 0, 0, 128, 63,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 31, 0, 0, 2,
+ 5, 0, 0, 128, 0, 0,
+ 15, 144, 31, 0, 0, 2,
+ 5, 0, 1, 128, 1, 0,
+ 15, 144, 31, 0, 0, 2,
+ 5, 0, 2, 128, 2, 0,
+ 15, 144, 1, 0, 0, 2,
+ 0, 0, 15, 224, 1, 0,
+ 228, 128, 1, 0, 0, 2,
+ 1, 0, 3, 224, 2, 0,
+ 228, 128, 5, 0, 0, 3,
+ 1, 0, 15, 128, 0, 0,
+ 0, 128, 0, 0, 228, 160,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 1, 0, 228, 160,
+ 0, 0, 85, 128, 1, 0,
+ 228, 128, 1, 0, 0, 2,
+ 1, 0, 3, 128, 4, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 2, 0,
+ 228, 160, 1, 0, 0, 128,
+ 0, 0, 228, 128, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 3, 0, 228, 160, 1, 0,
+ 85, 128, 0, 0, 228, 128,
+ 1, 0, 0, 2, 0, 0,
+ 15, 192, 0, 0, 228, 128,
+ 255, 255, 0, 0, 88, 78,
+ 65, 80, 192, 0, 0, 0,
+ 192, 0, 0, 0, 0, 2,
+ 254, 255, 144, 0, 0, 0,
+ 48, 0, 0, 0, 1, 0,
+ 36, 0, 0, 0, 48, 0,
+ 0, 0, 48, 0, 0, 0,
+ 36, 0, 0, 0, 48, 0,
+ 0, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 2, 254, 255, 81, 0,
+ 0, 5, 4, 0, 15, 160,
+ 0, 0, 0, 0, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 5, 0, 0, 128,
+ 0, 0, 15, 144, 5, 0,
+ 0, 3, 1, 0, 15, 128,
+ 0, 0, 0, 128, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 1, 0,
+ 228, 160, 0, 0, 85, 128,
+ 1, 0, 228, 128, 1, 0,
+ 0, 2, 1, 0, 3, 128,
+ 4, 0, 228, 160, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 2, 0, 228, 160, 1, 0,
+ 0, 128, 0, 0, 228, 128,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 3, 0, 228, 160,
+ 1, 0, 85, 128, 0, 0,
+ 228, 128, 1, 0, 0, 2,
+ 0, 0, 15, 192, 0, 0,
+ 228, 128, 255, 255, 0, 0,
+ 65, 111, 110, 57, 20, 1,
+ 0, 0, 20, 1, 0, 0,
+ 0, 2, 254, 255, 224, 0,
+ 0, 0, 52, 0, 0, 0,
+ 1, 0, 36, 0, 0, 0,
+ 48, 0, 0, 0, 48, 0,
+ 0, 0, 36, 0, 1, 0,
+ 48, 0, 0, 0, 0, 0,
+ 4, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 2, 254, 255, 81, 0,
+ 0, 5, 5, 0, 15, 160,
+ 0, 0, 0, 0, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 5, 0, 0, 128,
+ 0, 0, 15, 144, 31, 0,
+ 0, 2, 5, 0, 1, 128,
+ 1, 0, 15, 144, 31, 0,
+ 0, 2, 5, 0, 2, 128,
+ 2, 0, 15, 144, 5, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 0, 144, 1, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 2, 0,
+ 228, 160, 0, 0, 85, 144,
+ 0, 0, 228, 128, 1, 0,
+ 0, 2, 1, 0, 3, 128,
+ 5, 0, 228, 160, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 3, 0, 228, 160, 1, 0,
+ 0, 128, 0, 0, 228, 128,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 4, 0, 228, 160,
+ 1, 0, 85, 128, 0, 0,
+ 228, 128, 5, 0, 0, 3,
+ 1, 0, 3, 128, 0, 0,
+ 255, 128, 0, 0, 228, 160,
+ 2, 0, 0, 3, 0, 0,
+ 3, 192, 0, 0, 228, 128,
+ 1, 0, 228, 128, 1, 0,
+ 0, 2, 0, 0, 12, 192,
+ 0, 0, 228, 128, 1, 0,
+ 0, 2, 0, 0, 15, 224,
+ 1, 0, 228, 144, 1, 0,
+ 0, 2, 1, 0, 3, 224,
+ 2, 0, 228, 144, 255, 255,
+ 0, 0, 83, 72, 68, 82,
+ 72, 1, 0, 0, 64, 0,
+ 1, 0, 82, 0, 0, 0,
+ 89, 0, 0, 4, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 0, 0, 0, 0, 95, 0,
+ 0, 3, 242, 16, 16, 0,
+ 1, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 2, 0, 0, 0, 103, 0,
+ 0, 4, 242, 32, 16, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 101, 0, 0, 3,
+ 242, 32, 16, 0, 1, 0,
+ 0, 0, 101, 0, 0, 3,
+ 50, 32, 16, 0, 2, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 56, 0,
+ 0, 8, 242, 0, 16, 0,
+ 0, 0, 0, 0, 6, 16,
+ 16, 0, 0, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 50, 0, 0, 10, 242, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 86, 21, 16, 0, 0, 0,
+ 0, 0, 70, 14, 16, 0,
+ 0, 0, 0, 0, 50, 0,
+ 0, 13, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 70, 14, 16, 0, 0, 0,
+ 0, 0, 50, 0, 0, 13,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 70, 142, 32, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 128, 63, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 0, 0, 128, 63, 70, 14,
+ 16, 0, 0, 0, 0, 0,
+ 54, 0, 0, 5, 242, 32,
+ 16, 0, 1, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 50, 32, 16, 0, 2, 0,
+ 0, 0, 70, 16, 16, 0,
+ 2, 0, 0, 0, 62, 0,
+ 0, 1, 73, 83, 71, 78,
+ 104, 0, 0, 0, 3, 0,
+ 0, 0, 8, 0, 0, 0,
+ 80, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 0, 0,
+ 89, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 15, 0, 0,
+ 95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 2, 0,
+ 0, 0, 3, 3, 0, 0,
+ 80, 79, 83, 73, 84, 73,
+ 79, 78, 0, 67, 79, 76,
+ 79, 82, 0, 84, 69, 88,
+ 67, 79, 79, 82, 68, 0,
+ 79, 83, 71, 78, 108, 0,
+ 0, 0, 3, 0, 0, 0,
+ 8, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 15, 0, 0, 0, 98, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 0, 0, 0,
+ 3, 12, 0, 0, 83, 86,
+ 95, 80, 79, 83, 73, 84,
+ 73, 79, 78, 0, 67, 79,
+ 76, 79, 82, 0, 84, 69,
+ 88, 67, 79, 79, 82, 68,
+ 0, 171
+};
diff --git a/nuklear/demo/gdi/build.bat b/nuklear/demo/gdi/build.bat
new file mode 100644
index 0000000..3884317
--- /dev/null
+++ b/nuklear/demo/gdi/build.bat
@@ -0,0 +1,6 @@
+@echo off
+
+rem This will use VS2015 for compiler
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdi32.lib /link /incremental:no
diff --git a/nuklear/demo/gdi/main.c b/nuklear/demo/gdi/main.c
new file mode 100644
index 0000000..e82cd16
--- /dev/null
+++ b/nuklear/demo/gdi/main.c
@@ -0,0 +1,161 @@
+/* nuklear - v1.17 - public domain */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDI_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_gdi.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+#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])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ if (nk_gdi_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ GdiFont* font;
+ struct nk_context *ctx;
+
+ WNDCLASSW wc;
+ ATOM atom;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ HDC dc;
+ int running = 1;
+ int needs_refresh = 1;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ atom = RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+ dc = GetDC(wnd);
+
+ /* GUI */
+ font = nk_gdifont_create("Arial", 14);
+ ctx = nk_gdi_init(font, dc, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ if (needs_refresh == 0) {
+ if (GetMessageW(&msg, NULL, 0, 0) <= 0)
+ running = 0;
+ else {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ needs_refresh = 1;
+ } else needs_refresh = 0;
+
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ needs_refresh = 1;
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ 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"))
+ 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_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ nk_gdi_render(nk_rgb(30,30,30));
+ }
+
+ nk_gdifont_del(font);
+ ReleaseDC(wnd, dc);
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
+
diff --git a/nuklear/demo/gdi/nuklear_gdi.h b/nuklear/demo/gdi/nuklear_gdi.h
new file mode 100644
index 0000000..6d3a84a
--- /dev/null
+++ b/nuklear/demo/gdi/nuklear_gdi.h
@@ -0,0 +1,761 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GDI_H_
+#define NK_GDI_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct GdiFont GdiFont;
+NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);
+NK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_gdi_render(struct nk_color clear);
+NK_API void nk_gdi_shutdown(void);
+
+/* font */
+NK_API GdiFont* nk_gdifont_create(const char *name, int size);
+NK_API void nk_gdifont_del(GdiFont *font);
+NK_API void nk_gdi_set_font(GdiFont *font);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GDI_IMPLEMENTATION
+
+#include <stdlib.h>
+#include <malloc.h>
+
+struct GdiFont {
+ struct nk_user_font nk;
+ int height;
+ HFONT handle;
+ HDC dc;
+};
+
+static struct {
+ HBITMAP bitmap;
+ HDC window_dc;
+ HDC memory_dc;
+ unsigned int width;
+ unsigned int height;
+ struct nk_context ctx;
+} gdi;
+
+static COLORREF
+convert_color(struct nk_color c)
+{
+ return c.r | (c.g << 8) | (c.b << 16);
+}
+
+static void
+nk_gdi_scissor(HDC dc, float x, float y, float w, float h)
+{
+ SelectClipRgn(dc, NULL);
+ IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1));
+}
+
+static void
+nk_gdi_stroke_line(HDC dc, short x0, short y0, short x1,
+ short y1, unsigned int line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ MoveToEx(dc, x0, y0, NULL);
+ LineTo(dc, x1, y1);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ if (r == 0) {
+ Rectangle(dc, x, y, x + w, y + h);
+ } else {
+ RoundRect(dc, x, y, x + w, y + h, r, r);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ if (r == 0) {
+ RECT rect = { x, y, x + w, y + h };
+ SetBkColor(dc, color);
+ ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
+ } else {
+ SetDCPenColor(dc, color);
+ SetDCBrushColor(dc, color);
+ RoundRect(dc, x, y, x + w, y + h, r, r);
+ }
+}
+
+static void
+nk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1,
+ short y1, short x2, short y2, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ };
+
+ SetDCPenColor(dc, color);
+ SetDCBrushColor(dc, color);
+ Polygon(dc, points, 3);
+}
+
+static void
+nk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1,
+ short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ { x0, y0 },
+ };
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ Polyline(dc, points, 4);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_polygon(HDC dc, const struct nk_vec2i *pnts, int count, struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 64
+ POINT points[MAX_POINTS];
+ COLORREF color = convert_color(col);
+ SetDCBrushColor(dc, color);
+ SetDCPenColor(dc, color);
+ for (i = 0; i < count && i < MAX_POINTS; ++i) {
+ points[i].x = pnts[i].x;
+ points[i].y = pnts[i].y;
+ }
+ Polygon(dc, points, i);
+ #undef MAX_POINTS
+}
+
+static void
+nk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i *pnts, int count,
+ unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ if (count > 0) {
+ int i;
+ MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
+ for (i = 1; i < count; ++i)
+ LineTo(dc, pnts[i].x, pnts[i].y);
+ LineTo(dc, pnts[0].x, pnts[0].y);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i *pnts,
+ int count, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ if (count > 0) {
+ int i;
+ MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
+ for (i = 1; i < count; ++i)
+ LineTo(dc, pnts[i].x, pnts[i].y);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ SetDCBrushColor(dc, color);
+ SetDCPenColor(dc, color);
+ Ellipse(dc, x, y, x + w, y + h);
+}
+
+static void
+nk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ Ellipse(dc, x, y, x + w, y + h);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1,
+ struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+ unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT p[] = {
+ { p1.x, p1.y },
+ { p2.x, p2.y },
+ { p3.x, p3.y },
+ { p4.x, p4.y },
+ };
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ PolyBezier(dc, p, 4);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h,
+ const char *text, int len, GdiFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+ int wsize;
+ WCHAR* wstr;
+
+ if(!text || !font || !len) return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ SetBkColor(dc, convert_color(cbg));
+ SetTextColor(dc, convert_color(cfg));
+
+ SelectObject(dc, font->handle);
+ ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL);
+}
+
+static void
+nk_gdi_clear(HDC dc, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ RECT rect = { 0, 0, gdi.width, gdi.height };
+ SetBkColor(dc, color);
+
+ ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
+}
+
+static void
+nk_gdi_blit(HDC dc)
+{
+ BitBlt(dc, 0, 0, gdi.width, gdi.height, gdi.memory_dc, 0, 0, SRCCOPY);
+}
+
+GdiFont*
+nk_gdifont_create(const char *name, int size)
+{
+ TEXTMETRICW metric;
+ GdiFont *font = (GdiFont*)calloc(1, sizeof(GdiFont));
+ if (!font)
+ return NULL;
+ font->dc = CreateCompatibleDC(0);
+ font->handle = CreateFont(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);
+ SelectObject(font->dc, font->handle);
+ GetTextMetricsW(font->dc, &metric);
+ font->height = metric.tmHeight;
+ return font;
+}
+
+static float
+nk_gdifont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ GdiFont *font = (GdiFont*)handle.ptr;
+ SIZE size;
+ int wsize;
+ WCHAR* wstr;
+ if (!font || !text)
+ return 0;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size))
+ return (float)size.cx;
+ return -1.0f;
+}
+
+void
+nk_gdifont_del(GdiFont *font)
+{
+ if(!font) return;
+ DeleteObject(font->handle);
+ DeleteDC(font->dc);
+ free(font);
+}
+
+static void
+nk_gdi_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ (void)usr;
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ {
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem)
+ {
+ SIZE_T size = GlobalSize(mem) - 1;
+ if (size)
+ {
+ LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+ if (wstr)
+ {
+ int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
+ if (utf8size)
+ {
+ char* utf8 = (char*)malloc(utf8size);
+ if (utf8)
+ {
+ WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ }
+ }
+ GlobalUnlock(mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+static void
+nk_gdi_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ if (OpenClipboard(NULL))
+ {
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (wsize)
+ {
+ HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (mem)
+ {
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (wstr)
+ {
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+NK_API struct nk_context*
+nk_gdi_init(GdiFont *gdifont, HDC window_dc, unsigned int width, unsigned int height)
+{
+ struct nk_user_font *font = &gdifont->nk;
+ font->userdata = nk_handle_ptr(gdifont);
+ font->height = (float)gdifont->height;
+ font->width = nk_gdifont_get_text_width;
+
+ gdi.bitmap = CreateCompatibleBitmap(window_dc, width, height);
+ gdi.window_dc = window_dc;
+ gdi.memory_dc = CreateCompatibleDC(window_dc);
+ gdi.width = width;
+ gdi.height = height;
+ SelectObject(gdi.memory_dc, gdi.bitmap);
+
+ nk_init_default(&gdi.ctx, font);
+ gdi.ctx.clip.copy = nk_gdi_clipbard_copy;
+ gdi.ctx.clip.paste = nk_gdi_clipbard_paste;
+ return &gdi.ctx;
+}
+
+NK_API void
+nk_gdi_set_font(GdiFont *gdifont)
+{
+ struct nk_user_font *font = &gdifont->nk;
+ font->userdata = nk_handle_ptr(gdifont);
+ font->height = (float)gdifont->height;
+ font->width = nk_gdifont_get_text_width;
+ nk_style_set_font(&gdi.ctx, font);
+}
+
+NK_API int
+nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_SIZE:
+ {
+ unsigned width = LOWORD(lparam);
+ unsigned height = LOWORD(lparam);
+ if (width != gdi.width || height != gdi.height)
+ {
+ DeleteObject(gdi.bitmap);
+ gdi.bitmap = CreateCompatibleBitmap(gdi.window_dc, width, height);
+ gdi.width = width;
+ gdi.height = height;
+ SelectObject(gdi.memory_dc, gdi.bitmap);
+ }
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT paint;
+ HDC dc = BeginPaint(wnd, &paint);
+ nk_gdi_blit(dc);
+ EndPaint(wnd, &paint);
+ return 1;
+ }
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&gdi.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&gdi.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&gdi.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&gdi.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&gdi.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&gdi.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&gdi.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&gdi.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&gdi.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+NK_API void
+nk_gdi_shutdown(void)
+{
+ DeleteObject(gdi.memory_dc);
+ DeleteObject(gdi.bitmap);
+ nk_free(&gdi.ctx);
+}
+
+NK_API void
+nk_gdi_render(struct nk_color clear)
+{
+ const struct nk_command *cmd;
+
+ HDC memory_dc = gdi.memory_dc;
+ SelectObject(memory_dc, GetStockObject(DC_PEN));
+ SelectObject(memory_dc, GetStockObject(DC_BRUSH));
+ nk_gdi_clear(memory_dc, clear);
+
+ nk_foreach(cmd, &gdi.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_gdi_scissor(memory_dc, 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_gdi_stroke_line(memory_dc, 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_gdi_stroke_rect(memory_dc, 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_gdi_fill_rect(memory_dc, 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_gdi_stroke_circle(memory_dc, 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_gdi_fill_circle(memory_dc, 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_gdi_stroke_triangle(memory_dc, 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_gdi_fill_triangle(memory_dc, 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_gdi_stroke_polygon(memory_dc, 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_gdi_fill_polygon(memory_dc, 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_gdi_stroke_polyline(memory_dc, 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_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h,
+ (const char*)t->string, t->length,
+ (GdiFont*)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_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1],
+ q->end, 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_gdi_blit(gdi.window_dc);
+ nk_clear(&gdi.ctx);
+}
+
+#endif
+
diff --git a/nuklear/demo/gdip/build.bat b/nuklear/demo/gdip/build.bat
new file mode 100644
index 0000000..28f51a3
--- /dev/null
+++ b/nuklear/demo/gdip/build.bat
@@ -0,0 +1,5 @@
+@echo off
+
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdiplus.lib /link /incremental:no
diff --git a/nuklear/demo/gdip/main.c b/nuklear/demo/gdip/main.c
new file mode 100644
index 0000000..7d623e7
--- /dev/null
+++ b/nuklear/demo/gdip/main.c
@@ -0,0 +1,155 @@
+/* nuklear - v1.17 - public domain */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDIP_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_gdip.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* These are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #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])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+ if (nk_gdip_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ GdipFont* font;
+ struct nk_context *ctx;
+
+ WNDCLASSW wc;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ int running = 1;
+ int needs_refresh = 1;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+
+ /* GUI */
+ ctx = nk_gdip_init(wnd, WINDOW_WIDTH, WINDOW_HEIGHT);
+ font = nk_gdipfont_create("Arial", 12);
+ nk_gdip_set_font(font);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ if (needs_refresh == 0) {
+ if (GetMessageW(&msg, NULL, 0, 0) <= 0)
+ running = 0;
+ else {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ needs_refresh = 1;
+ } else needs_refresh = 0;
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ needs_refresh = 1;
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ 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"))
+ 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_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ nk_gdip_render(NK_ANTI_ALIASING_ON, nk_rgb(30,30,30));
+ }
+
+ nk_gdipfont_del(font);
+ nk_gdip_shutdown();
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
diff --git a/nuklear/demo/gdip/nuklear_gdip.h b/nuklear/demo/gdip/nuklear_gdip.h
new file mode 100644
index 0000000..66ccc0d
--- /dev/null
+++ b/nuklear/demo/gdip/nuklear_gdip.h
@@ -0,0 +1,1006 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GDIP_H_
+#define NK_GDIP_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* font */
+typedef struct GdipFont GdipFont;
+NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
+NK_API void nk_gdipfont_del(GdipFont *font);
+
+NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height);
+NK_API void nk_gdip_set_font(GdipFont *font);
+NK_API int nk_gdip_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear);
+NK_API void nk_gdip_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GDIP_IMPLEMENTATION
+
+#include <stdlib.h>
+#include <malloc.h>
+
+/* manually declare everything GDI+ needs, because
+ GDI+ headers are not usable from C */
+#define WINGDIPAPI __stdcall
+#define GDIPCONST const
+
+typedef struct GpGraphics GpGraphics;
+typedef struct GpImage GpImage;
+typedef struct GpPen GpPen;
+typedef struct GpBrush GpBrush;
+typedef struct GpStringFormat GpStringFormat;
+typedef struct GpFont GpFont;
+typedef struct GpFontFamily GpFontFamily;
+typedef struct GpFontCollection GpFontCollection;
+
+typedef GpImage GpBitmap;
+typedef GpBrush GpSolidFill;
+
+typedef int Status;
+typedef Status GpStatus;
+
+typedef float REAL;
+typedef DWORD ARGB;
+typedef POINT GpPoint;
+
+typedef enum {
+ TextRenderingHintSystemDefault = 0,
+ TextRenderingHintSingleBitPerPixelGridFit = 1,
+ TextRenderingHintSingleBitPerPixel = 2,
+ TextRenderingHintAntiAliasGridFit = 3,
+ TextRenderingHintAntiAlias = 4,
+ TextRenderingHintClearTypeGridFit = 5
+} TextRenderingHint;
+
+typedef enum {
+ StringFormatFlagsDirectionRightToLeft = 0x00000001,
+ StringFormatFlagsDirectionVertical = 0x00000002,
+ StringFormatFlagsNoFitBlackBox = 0x00000004,
+ StringFormatFlagsDisplayFormatControl = 0x00000020,
+ StringFormatFlagsNoFontFallback = 0x00000400,
+ StringFormatFlagsMeasureTrailingSpaces = 0x00000800,
+ StringFormatFlagsNoWrap = 0x00001000,
+ StringFormatFlagsLineLimit = 0x00002000,
+ StringFormatFlagsNoClip = 0x00004000
+} StringFormatFlags;
+
+typedef enum
+{
+ QualityModeInvalid = -1,
+ QualityModeDefault = 0,
+ QualityModeLow = 1,
+ QualityModeHigh = 2
+} QualityMode;
+
+typedef enum
+{
+ SmoothingModeInvalid = QualityModeInvalid,
+ SmoothingModeDefault = QualityModeDefault,
+ SmoothingModeHighSpeed = QualityModeLow,
+ SmoothingModeHighQuality = QualityModeHigh,
+ SmoothingModeNone,
+ SmoothingModeAntiAlias,
+ SmoothingModeAntiAlias8x4 = SmoothingModeAntiAlias,
+ SmoothingModeAntiAlias8x8
+} SmoothingMode;
+
+typedef enum
+{
+ FontStyleRegular = 0,
+ FontStyleBold = 1,
+ FontStyleItalic = 2,
+ FontStyleBoldItalic = 3,
+ FontStyleUnderline = 4,
+ FontStyleStrikeout = 8
+} FontStyle;
+
+typedef enum {
+ FillModeAlternate,
+ FillModeWinding
+} FillMode;
+
+typedef enum {
+ CombineModeReplace,
+ CombineModeIntersect,
+ CombineModeUnion,
+ CombineModeXor,
+ CombineModeExclude,
+ CombineModeComplement
+} CombineMode;
+
+typedef enum {
+ UnitWorld,
+ UnitDisplay,
+ UnitPixel,
+ UnitPoint,
+ UnitInch,
+ UnitDocument,
+ UnitMillimeter
+} Unit;
+
+typedef struct {
+ FLOAT X;
+ FLOAT Y;
+ FLOAT Width;
+ FLOAT Height;
+} RectF;
+
+typedef enum {
+ DebugEventLevelFatal,
+ DebugEventLevelWarning
+} DebugEventLevel;
+
+typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
+
+typedef struct {
+ UINT32 GdiplusVersion;
+ DebugEventProc DebugEventCallback;
+ BOOL SuppressBackgroundThread;
+ BOOL SuppressExternalCodecs;
+} GdiplusStartupInput;
+
+typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
+typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);
+
+typedef struct {
+ NotificationHookProc NotificationHook;
+ NotificationUnhookProc NotificationUnhook;
+} GdiplusStartupOutput;
+
+/* startup & shutdown */
+
+Status WINAPI GdiplusStartup(
+ OUT ULONG_PTR *token,
+ const GdiplusStartupInput *input,
+ OUT GdiplusStartupOutput *output);
+
+VOID WINAPI GdiplusShutdown(ULONG_PTR token);
+
+/* image */
+
+GpStatus WINGDIPAPI
+GdipCreateBitmapFromGraphics(INT width,
+ INT height,
+ GpGraphics* target,
+ GpBitmap** bitmap);
+
+GpStatus WINGDIPAPI
+GdipDisposeImage(GpImage *image);
+
+GpStatus WINGDIPAPI
+GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics);
+
+/* pen */
+
+GpStatus WINGDIPAPI
+GdipCreatePen1(ARGB color, REAL width, Unit unit, GpPen **pen);
+
+GpStatus WINGDIPAPI
+GdipDeletePen(GpPen *pen);
+
+GpStatus WINGDIPAPI
+GdipSetPenWidth(GpPen *pen, REAL width);
+
+GpStatus WINGDIPAPI
+GdipSetPenColor(GpPen *pen, ARGB argb);
+
+/* brush */
+
+GpStatus WINGDIPAPI
+GdipCreateSolidFill(ARGB color, GpSolidFill **brush);
+
+GpStatus WINGDIPAPI
+GdipDeleteBrush(GpBrush *brush);
+
+GpStatus WINGDIPAPI
+GdipSetSolidFillColor(GpSolidFill *brush, ARGB color);
+
+/* font */
+
+GpStatus WINGDIPAPI
+GdipCreateFont(
+ GDIPCONST GpFontFamily *fontFamily,
+ REAL emSize,
+ INT style,
+ Unit unit,
+ GpFont **font
+);
+
+GpStatus WINGDIPAPI
+GdipDeleteFont(GpFont* font);
+
+GpStatus WINGDIPAPI
+GdipGetFontSize(GpFont *font, REAL *size);
+
+GpStatus WINGDIPAPI
+GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name,
+ GpFontCollection *fontCollection,
+ GpFontFamily **fontFamily);
+
+GpStatus WINGDIPAPI
+GdipDeleteFontFamily(GpFontFamily *fontFamily);
+
+GpStatus WINGDIPAPI
+GdipStringFormatGetGenericTypographic(GpStringFormat **format);
+
+GpStatus WINGDIPAPI
+GdipSetStringFormatFlags(GpStringFormat *format, INT flags);
+
+GpStatus WINGDIPAPI
+GdipDeleteStringFormat(GpStringFormat *format);
+
+/* graphics */
+
+
+GpStatus WINGDIPAPI
+GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics);
+
+GpStatus WINGDIPAPI
+GdipCreateFromHDC(HDC hdc, GpGraphics **graphics);
+
+GpStatus WINGDIPAPI
+GdipDeleteGraphics(GpGraphics *graphics);
+
+GpStatus WINGDIPAPI
+GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode);
+
+GpStatus WINGDIPAPI
+GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
+ INT width, INT height, CombineMode combineMode);
+
+GpStatus WINGDIPAPI
+GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,
+ INT x2, INT y2);
+
+GpStatus WINGDIPAPI
+GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height, REAL startAngle, REAL sweepAngle);
+
+GpStatus WINGDIPAPI
+GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height, REAL startAngle, REAL sweepAngle);
+
+GpStatus WINGDIPAPI
+GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
+ GDIPCONST GpPoint *points, INT count, FillMode fillMode);
+
+GpStatus WINGDIPAPI
+GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points,
+ INT count);
+
+GpStatus WINGDIPAPI
+GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,
+ INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);
+
+GpStatus WINGDIPAPI
+GdipDrawString(
+ GpGraphics *graphics,
+ GDIPCONST WCHAR *string,
+ INT length,
+ GDIPCONST GpFont *font,
+ GDIPCONST RectF *layoutRect,
+ GDIPCONST GpStringFormat *stringFormat,
+ GDIPCONST GpBrush *brush
+);
+
+GpStatus WINGDIPAPI
+GdipGraphicsClear(GpGraphics *graphics, ARGB color);
+
+GpStatus WINGDIPAPI
+GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, INT y);
+
+GpStatus WINGDIPAPI
+GdipMeasureString(
+ GpGraphics *graphics,
+ GDIPCONST WCHAR *string,
+ INT length,
+ GDIPCONST GpFont *font,
+ GDIPCONST RectF *layoutRect,
+ GDIPCONST GpStringFormat *stringFormat,
+ RectF *boundingBox,
+ INT *codepointsFitted,
+ INT *linesFilled
+);
+
+GpStatus WINGDIPAPI
+GdipSetTextRenderingHint(GpGraphics *graphics, TextRenderingHint mode);
+
+struct GdipFont
+{
+ struct nk_user_font nk;
+ GpFont* handle;
+};
+
+static struct {
+ ULONG_PTR token;
+
+ GpGraphics *window;
+ GpGraphics *memory;
+ GpImage *bitmap;
+ GpPen *pen;
+ GpSolidFill *brush;
+ GpStringFormat *format;
+
+ struct nk_context ctx;
+} gdip;
+
+static ARGB convert_color(struct nk_color c)
+{
+ return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b;
+}
+
+static void
+nk_gdip_scissor(float x, float y, float w, float h)
+{
+ GdipSetClipRectI(gdip.memory, (INT)x, (INT)y, (INT)(w + 1), (INT)(h + 1), CombineModeReplace);
+}
+
+static void
+nk_gdip_stroke_line(short x0, short y0, short x1,
+ short y1, unsigned int line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawLineI(gdip.memory, gdip.pen, x0, y0, x1, y1);
+}
+
+static void
+nk_gdip_stroke_rect(short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (r == 0) {
+ GdipDrawRectangleI(gdip.memory, gdip.pen, x, y, w, h);
+ } else {
+ INT d = 2 * r;
+ GdipDrawArcI(gdip.memory, gdip.pen, x, y, d, d, 180, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + d, y, x + w - d, y);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + d, x + w, y + h - d);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x, y + d, x + w, y + h - d);
+ GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + d, y + h, x + w - d, y + h);
+ }
+}
+
+static void
+nk_gdip_fill_rect(short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, struct nk_color col)
+{
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ if (r == 0) {
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);
+ } else {
+ INT d = 2 * r;
+ GdipFillRectangleI(gdip.memory, gdip.brush, x + r, y, w - d, h);
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y + r, w, h - d);
+ GdipFillPieI(gdip.memory, gdip.brush, x, y, d, d, 180, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y, d, d, 270, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y + h - d, d, d, 0, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x, y + h - d, d, d, 90, 90);
+ }
+}
+
+static void
+nk_gdip_fill_triangle(short x0, short y0, short x1,
+ short y1, short x2, short y2, struct nk_color col)
+{
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ };
+
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ GdipFillPolygonI(gdip.memory, gdip.brush, points, 3, FillModeAlternate);
+}
+
+static void
+nk_gdip_stroke_triangle(short x0, short y0, short x1,
+ short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ { x0, y0 },
+ };
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawPolygonI(gdip.memory, gdip.pen, points, 4);
+}
+
+static void
+nk_gdip_fill_polygon(const struct nk_vec2i *pnts, int count, struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 64
+ POINT points[MAX_POINTS];
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ for (i = 0; i < count && i < MAX_POINTS; ++i) {
+ points[i].x = pnts[i].x;
+ points[i].y = pnts[i].y;
+ }
+ GdipFillPolygonI(gdip.memory, gdip.brush, points, i, FillModeAlternate);
+ #undef MAX_POINTS
+}
+
+static void
+nk_gdip_stroke_polygon(const struct nk_vec2i *pnts, int count,
+ unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (count > 0) {
+ int i;
+ for (i = 1; i < count; ++i)
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
+ }
+}
+
+static void
+nk_gdip_stroke_polyline(const struct nk_vec2i *pnts,
+ int count, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (count > 0) {
+ int i;
+ for (i = 1; i < count; ++i)
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+ }
+}
+
+static void
+nk_gdip_fill_circle(short x, short y, unsigned short w,
+ unsigned short h, struct nk_color col)
+{
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ GdipFillEllipseI(gdip.memory, gdip.brush, x, y, w, h);
+}
+
+static void
+nk_gdip_stroke_circle(short x, short y, unsigned short w,
+ unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawEllipseI(gdip.memory, gdip.pen, x, y, w, h);
+}
+
+static void
+nk_gdip_stroke_curve(struct nk_vec2i p1,
+ struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+ unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawBezierI(gdip.memory, gdip.pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
+}
+
+static void
+nk_gdip_draw_text(short x, short y, unsigned short w, unsigned short h,
+ const char *text, int len, GdipFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+ int wsize;
+ WCHAR* wstr;
+ RectF layout = { (FLOAT)x, (FLOAT)y, (FLOAT)w, (FLOAT)h };
+
+ if(!text || !font || !len) return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ GdipSetSolidFillColor(gdip.brush, convert_color(cbg));
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);
+ GdipSetSolidFillColor(gdip.brush, convert_color(cfg));
+ GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush);
+}
+
+static void
+nk_gdip_clear(struct nk_color col)
+{
+ GdipGraphicsClear(gdip.memory, convert_color(col));
+}
+
+static void
+nk_gdip_blit(GpGraphics *graphics)
+{
+ GdipDrawImageI(graphics, gdip.bitmap, 0, 0);
+}
+
+GdipFont*
+nk_gdipfont_create(const char *name, int size)
+{
+ GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont));
+ GpFontFamily *family;
+
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+ WCHAR* wname = (WCHAR*)_alloca((wsize + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, wsize);
+ wname[wsize] = 0;
+
+ GdipCreateFontFamilyFromName(wname, NULL, &family);
+ GdipCreateFont(family, (REAL)size, FontStyleRegular, UnitPixel, &font->handle);
+ GdipDeleteFontFamily(family);
+
+ return font;
+}
+
+static float
+nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ GdipFont *font = (GdipFont *)handle.ptr;
+ RectF layout = { 0.0f, 0.0f, 65536.0f, 65536.0f };
+ RectF bbox;
+ int wsize;
+ WCHAR* wstr;
+ if (!font || !text)
+ return 0;
+
+ (void)height;
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ GdipMeasureString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, &bbox, NULL, NULL);
+ return bbox.Width;
+}
+
+void
+nk_gdipfont_del(GdipFont *font)
+{
+ if(!font) return;
+ GdipDeleteFont(font->handle);
+ free(font);
+}
+
+static void
+nk_gdip_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ HGLOBAL mem;
+ SIZE_T size;
+ LPCWSTR wstr;
+ int utf8size;
+ char* utf8;
+ (void)usr;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ return;
+
+ mem = (HGLOBAL)GetClipboardData(CF_UNICODETEXT);
+ if (!mem) {
+ CloseClipboard();
+ return;
+ }
+
+ size = GlobalSize(mem) - 1;
+ if (!size) {
+ CloseClipboard();
+ return;
+ }
+
+ wstr = (LPCWSTR)GlobalLock(mem);
+ if (!wstr) {
+ CloseClipboard();
+ return;
+ }
+
+ utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
+ if (!utf8size) {
+ GlobalUnlock(mem);
+ CloseClipboard();
+ return;
+ }
+
+ utf8 = (char*)malloc(utf8size);
+ if (!utf8) {
+ GlobalUnlock(mem);
+ CloseClipboard();
+ return;
+ }
+
+ WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ GlobalUnlock(mem);
+ CloseClipboard();
+}
+
+static void
+nk_gdip_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ HGLOBAL mem;
+ wchar_t* wstr;
+ int wsize;
+ (void)usr;
+
+ if (!OpenClipboard(NULL))
+ return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (!wsize) {
+ CloseClipboard();
+ return;
+ }
+
+ mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (!mem) {
+ CloseClipboard();
+ return;
+ }
+
+ wstr = (wchar_t*)GlobalLock(mem);
+ if (!wstr) {
+ GlobalFree(mem);
+ CloseClipboard();
+ return;
+ }
+
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+ if (!SetClipboardData(CF_UNICODETEXT, mem))
+ GlobalFree(mem);
+ CloseClipboard();
+}
+
+NK_API struct nk_context*
+nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height)
+{
+ GdiplusStartupInput startup = { 1, NULL, FALSE, TRUE };
+ GdiplusStartup(&gdip.token, &startup, NULL);
+
+ GdipCreateFromHWND(hwnd, &gdip.window);
+ GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);
+ GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);
+ GdipCreatePen1(0, 1.0f, UnitPixel, &gdip.pen);
+ GdipCreateSolidFill(0, &gdip.brush);
+ GdipStringFormatGetGenericTypographic(&gdip.format);
+ GdipSetStringFormatFlags(gdip.format, StringFormatFlagsNoFitBlackBox |
+ StringFormatFlagsMeasureTrailingSpaces | StringFormatFlagsNoWrap |
+ StringFormatFlagsNoClip);
+
+ nk_init_default(&gdip.ctx, NULL);
+ gdip.ctx.clip.copy = nk_gdip_clipbard_copy;
+ gdip.ctx.clip.paste = nk_gdip_clipbard_paste;
+ return &gdip.ctx;
+}
+
+NK_API void
+nk_gdip_set_font(GdipFont *gdipfont)
+{
+ struct nk_user_font *font = &gdipfont->nk;
+ font->userdata = nk_handle_ptr(gdipfont);
+ GdipGetFontSize(gdipfont->handle, &font->height);
+ font->width = nk_gdipfont_get_text_width;
+ nk_style_set_font(&gdip.ctx, font);
+}
+
+NK_API int
+nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_SIZE:
+ if (gdip.window)
+ {
+ unsigned int width = LOWORD(lparam);
+ unsigned int height = HIWORD(lparam);
+ GdipDeleteGraphics(gdip.window);
+ GdipDeleteGraphics(gdip.memory);
+ GdipDisposeImage(gdip.bitmap);
+ GdipCreateFromHWND(wnd, &gdip.window);
+ GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);
+ GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT paint;
+ HDC dc = BeginPaint(wnd, &paint);
+ GpGraphics *graphics;
+ GdipCreateFromHDC(dc, &graphics);
+ nk_gdip_blit(graphics);
+ GdipDeleteGraphics(graphics);
+ EndPaint(wnd, &paint);
+ return 1;
+ }
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&gdip.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&gdip.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&gdip.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&gdip.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&gdip.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&gdip.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&gdip.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&gdip.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&gdip.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+NK_API void
+nk_gdip_shutdown(void)
+{
+ GdipDeleteGraphics(gdip.window);
+ GdipDeleteGraphics(gdip.memory);
+ GdipDisposeImage(gdip.bitmap);
+ GdipDeletePen(gdip.pen);
+ GdipDeleteBrush(gdip.brush);
+ GdipDeleteStringFormat(gdip.format);
+ GdiplusShutdown(gdip.token);
+
+ nk_free(&gdip.ctx);
+}
+
+NK_API void
+nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear)
+{
+ const struct nk_command *cmd;
+
+ GdipSetTextRenderingHint(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?
+ TextRenderingHintClearTypeGridFit : TextRenderingHintSingleBitPerPixelGridFit);
+ GdipSetSmoothingMode(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?
+ SmoothingModeHighQuality : SmoothingModeNone);
+ nk_gdip_clear(clear);
+
+ nk_foreach(cmd, &gdip.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_gdip_scissor(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_gdip_stroke_line(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_gdip_stroke_rect(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_gdip_fill_rect(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_gdip_stroke_circle(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_gdip_fill_circle(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_gdip_stroke_triangle(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_gdip_fill_triangle(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_gdip_stroke_polygon(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_gdip_fill_polygon(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_gdip_stroke_polyline(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_gdip_draw_text(t->x, t->y, t->w, t->h,
+ (const char*)t->string, t->length,
+ (GdipFont*)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_gdip_stroke_curve(q->begin, q->ctrl[0], q->ctrl[1],
+ q->end, 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_gdip_blit(gdip.window);
+ nk_clear(&gdip.ctx);
+}
+
+#endif
+
diff --git a/nuklear/demo/glfw_opengl2/Makefile b/nuklear/demo/glfw_opengl2/Makefile
new file mode 100644
index 0000000..c937eb8
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lglfw3 -lopengl32 -lm -lGLU32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lglfw3 -framework OpenGL -lm
+ else
+ LIBS = -lglfw -lGL -lm -lGLU
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/glfw_opengl2/main.c b/nuklear/demo/glfw_opengl2/main.c
new file mode 100644
index 0000000..1c0f284
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/main.c
@@ -0,0 +1,165 @@
+/* nuklear - v1.17 - 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 <limits.h>
+#include <time.h>
+
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_GLFW_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_glfw_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+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);
+ }
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* GUI */
+ ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_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 *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_glfw3_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* Input */
+ glfwPollEvents();
+ nk_glfw3_new_frame();
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(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]);
+ /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state
+ * with blending, scissor, face culling and depth test and defaults everything
+ * back into a default state. Make sure to either save and restore or
+ * reset your own state after drawing rendering the UI. */
+ nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glfwSwapBuffers(win);}
+ }
+ nk_glfw3_shutdown();
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h b/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h
new file mode 100644
index 0000000..93af773
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h
@@ -0,0 +1,350 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GLFW_GL2_H_
+#define NK_GLFW_GL2_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_char_callback(GLFWwindow *win, unsigned int codepoint);
+NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GLFW_GL2_IMPLEMENTATION
+
+#ifndef NK_GLFW_TEXT_MAX
+#define NK_GLFW_TEXT_MAX 256
+#endif
+
+struct nk_glfw_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_glfw {
+ GLFWwindow *win;
+ int width, height;
+ int display_width, display_height;
+ struct nk_glfw_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_vec2 fb_scale;
+ unsigned int text[NK_GLFW_TEXT_MAX];
+ int text_len;
+ float scroll;
+} glfw;
+
+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_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_glfw_device *dev = &glfw.ogl;
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ 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 * glfw.fb_scale.x),
+ (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),
+ (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),
+ (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&glfw.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+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;
+}
+
+NK_INTERN 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;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ 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_buffer_init_default(&glfw.ogl.cmds);
+ 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;
+
+ glfwGetWindowSize(win, &glfw.width, &glfw.height);
+ glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);
+ glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;
+ glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;
+
+ nk_input_begin(ctx);
+ for (i = 0; i < glfw.text_len; ++i)
+ nk_input_unicode(ctx, glfw.text[i]);
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ else if (ctx->input.mouse.ungrab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
+ 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_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == 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) == GLFW_PRESS) {
+ 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);
+ if (ctx->input.mouse.grabbed) {
+ glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.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)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ nk_font_atlas_clear(&glfw.atlas);
+ nk_free(&glfw.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ memset(&glfw, 0, sizeof(glfw));
+}
+
+#endif
diff --git a/nuklear/demo/glfw_opengl3/Makefile b/nuklear/demo/glfw_opengl3/Makefile
new file mode 100644
index 0000000..7f620ea
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lglfw3 -framework OpenGL -lm -lGLEW
+ else
+ LIBS = -lglfw -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/glfw_opengl3/main.c b/nuklear/demo/glfw_opengl3/main.c
new file mode 100644
index 0000000..d74ee56
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/main.c
@@ -0,0 +1,180 @@
+/* nuklear - v1.17 - 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 <limits.h>
+#include <time.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_GLFW_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_glfw_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+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);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* 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 */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {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 *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_glfw3_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* Input */
+ glfwPollEvents();
+ nk_glfw3_new_frame();
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(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]);
+ /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glfwSwapBuffers(win);}
+ }
+ nk_glfw3_shutdown();
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h b/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h
new file mode 100644
index 0000000..aabb365
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h
@@ -0,0 +1,456 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GLFW_GL3_H_
+#define NK_GLFW_GL3_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_shutdown(void);
+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_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
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GLFW_GL3_IMPLEMENTATION
+
+#ifndef NK_GLFW_TEXT_MAX
+#define NK_GLFW_TEXT_MAX 256
+#endif
+
+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;
+};
+
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_glfw {
+ GLFWwindow *win;
+ int width, height;
+ int display_width, display_height;
+ struct nk_glfw_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_vec2 fb_scale;
+ unsigned int text[NK_GLFW_TEXT_MAX];
+ int text_len;
+ float scroll;
+} glfw;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+NK_API void
+nk_glfw3_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_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;
+ 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)glfw.width;
+ ortho[1][1] /= (GLfloat)glfw.height;
+
+ /* 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]);
+ glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);
+ {
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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 * glfw.fb_scale.x),
+ (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),
+ (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),
+ (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&glfw.ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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;
+}
+
+NK_INTERN 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;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ 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;
+
+ glfwGetWindowSize(win, &glfw.width, &glfw.height);
+ glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);
+ glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;
+ glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;
+
+ nk_input_begin(ctx);
+ for (i = 0; i < glfw.text_len; ++i)
+ nk_input_unicode(ctx, glfw.text[i]);
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ else if (ctx->input.mouse.ungrab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
+ 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_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == 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) == GLFW_PRESS) {
+ 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);
+ if (ctx->input.mouse.grabbed) {
+ glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.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();
+ memset(&glfw, 0, sizeof(glfw));
+}
+
+#endif
diff --git a/nuklear/demo/node_editor.c b/nuklear/demo/node_editor.c
new file mode 100644
index 0000000..6949f59
--- /dev/null
+++ b/nuklear/demo/node_editor.c
@@ -0,0 +1,343 @@
+/* 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 have connectors on the right position of the property that it links.
+ * This is mainly done out of laziness 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.*/
+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 {
+ int initialized;
+ 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 struct node_editor nodeEditor;
+
+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(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 node_editor *nodedit = &nodeEditor;
+
+ if (!nodeEditor.initialized) {
+ node_editor_init(&nodeEditor);
+ nodeEditor.initialized = 1;
+ }
+
+ if (nk_begin(ctx, "NodeEdit", nk_rect(0, 0, 800, 600),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE))
+ {
+ /* 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 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 movable group */
+ struct nk_panel *node;
+ 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, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE))
+ {
+ /* always have last selected node on top */
+
+ node = nk_window_get_panel(ctx);
+ 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);
+ 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;
+ 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 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, 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, "NodeEdit");
+}
+
diff --git a/nuklear/demo/overview.c b/nuklear/demo/overview.c
new file mode 100644
index 0000000..e271318
--- /dev/null
+++ b/nuklear/demo/overview.c
@@ -0,0 +1,1188 @@
+
+static int
+overview(struct nk_context *ctx)
+{
+ /* 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 movable = nk_true;
+ static int no_scrollbar = nk_false;
+ static nk_flags window_flags = 0;
+ static int minimizable = nk_true;
+
+ /* popups */
+ static enum nk_style_header_align header_align = NK_HEADER_RIGHT;
+ static int show_app_about = nk_false;
+
+ /* 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 (movable) window_flags |= NK_WINDOW_MOVABLE;
+ if (no_scrollbar) window_flags |= NK_WINDOW_NO_SCROLLBAR;
+ if (minimizable) window_flags |= NK_WINDOW_MINIMIZABLE;
+
+ if (nk_begin(ctx, "Overview", nk_rect(10, 10, 400, 600), window_flags))
+ {
+ if (show_menu)
+ {
+ /* menubar */
+ enum menu_states {MENU_DEFAULT, MENU_WINDOWS};
+ 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, 4);
+ nk_layout_row_push(ctx, 45);
+ if (nk_menu_begin_label(ctx, "MENU", NK_TEXT_LEFT, nk_vec2(120, 200)))
+ {
+ 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 */
+ static struct nk_rect s = {20, 100, 300, 190};
+ if (nk_popup_begin(ctx, 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 public domain License.", 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, "Movable", &movable);
+ nk_checkbox_label(ctx, "No Scrollbar", &no_scrollbar);
+ nk_checkbox_label(ctx, "Minimizable", &minimizable);
+ 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"))
+ fprintf(stdout, "Button pressed!\n");
+ nk_button_set_behavior(ctx, NK_BUTTON_REPEATER);
+ if (nk_button_label(ctx, "Repeater"))
+ fprintf(stdout, "Repeater is being pressed!\n");
+ nk_button_set_behavior(ctx, NK_BUTTON_DEFAULT);
+ nk_button_color(ctx, nk_rgb(0,0,255));
+
+ nk_layout_row_static(ctx, 25, 25, 8);
+ nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_SOLID);
+ nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_OUTLINE);
+ nk_button_symbol(ctx, NK_SYMBOL_RECT_SOLID);
+ nk_button_symbol(ctx, NK_SYMBOL_RECT_OUTLINE);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT);
+
+ nk_layout_row_static(ctx, 30, 100, 2);
+ nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_LEFT, "prev", NK_TEXT_RIGHT);
+ nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_RIGHT, "next", NK_TEXT_LEFT);
+ 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;
+
+ /* default combobox */
+ nk_layout_row_static(ctx, 25, 200, 1);
+ current_weapon = nk_combo(ctx, weapons, LEN(weapons), current_weapon, 25, nk_vec2(200,200));
+
+ /* slider color combobox */
+ if (nk_combo_begin_color(ctx, combo_color, nk_vec2(200,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_color2, nk_vec2(200,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, buffer, nk_vec2(200,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, buffer, nk_vec2(200,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, buffer, nk_vec2(200,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, buffer, nk_vec2(200,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, buffer, nk_vec2(200,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 */
+ 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, buffer, nk_vec2(350,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)) {
+ 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)) {
+ 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)) {
+ 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") ||
+ (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 retained mode and immediate 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)));
+ }
+
+ /* mixed 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)) {
+ nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);
+ nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);
+ for (id = 0, i = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ nk_chart_push_slot(ctx, (float)sin(id), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+
+ /* mixed colored chart */
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f);
+ for (id = 0, i = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ nk_chart_push_slot(ctx, (float)sin(id), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ 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, 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_layout_row_end(ctx);
+
+ if (nk_contextual_begin(ctx, 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"))
+ popup_active = 1;
+ nk_layout_row_end(ctx);
+
+ if (popup_active)
+ {
+ static struct nk_rect s = {20, 100, 220, 90};
+ if (nk_popup_begin(ctx, NK_POPUP_STATIC, "Error", 0, 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")) {
+ popup_active = 0;
+ nk_popup_close(ctx);
+ }
+ if (nk_button_label(ctx, "Cancel")) {
+ 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_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ 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_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ 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_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ 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_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ 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_layout_row_push(ctx, 0.6f);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 0.2f);
+ nk_button_label(ctx, "button");
+ nk_layout_row_end(ctx);
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Static immediate 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_layout_row_push(ctx, 200);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 50);
+ nk_button_label(ctx, "button");
+ 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_layout_space_push(ctx, nk_rect(0, 15, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_push(ctx, nk_rect(200, 15, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_push(ctx, nk_rect(100, 30, 100, 30));
+ nk_button_label(ctx, "button");
+ 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;
+
+ 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, "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, "Notebook", NK_MINIMIZED))
+ {
+ static int current_tab = 0;
+ struct nk_vec2 item_padding;
+ struct nk_rect bounds;
+ float step = (2*3.141592654f) / 32;
+ enum chart_type {CHART_LINE, CHART_HISTO, CHART_MIXED};
+ const char *names[] = {"Lines", "Columns", "Mixed"};
+ float id = 0;
+ int i;
+
+ /* Header */
+ nk_style_push_vec2(ctx, &ctx->style.window.spacing, nk_vec2(0,0));
+ nk_style_push_float(ctx, &ctx->style.button.rounding, 0);
+ nk_layout_row_begin(ctx, NK_STATIC, 20, 3);
+ for (i = 0; i < 3; ++i) {
+ /* make sure button perfectly fits text */
+ const struct nk_user_font *f = ctx->style.font;
+ float text_width = f->width(f->userdata, f->height, names[i], nk_strlen(names[i]));
+ float widget_width = text_width + 3 * ctx->style.button.padding.x;
+ nk_layout_row_push(ctx, widget_width);
+ if (current_tab == i) {
+ /* active tab gets highlighted */
+ struct nk_style_item button_color = ctx->style.button.normal;
+ ctx->style.button.normal = ctx->style.button.active;
+ current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;
+ ctx->style.button.normal = button_color;
+ } else current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;
+ }
+ nk_style_pop_float(ctx);
+
+ /* Body */
+ nk_layout_row_dynamic(ctx, 140, 1);
+ if (nk_group_begin(ctx, "Notebook", NK_WINDOW_BORDER))
+ {
+ nk_style_pop_vec2(ctx);
+ switch (current_tab) {
+ case CHART_LINE:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ case CHART_HISTO:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_COLUMN, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ case CHART_MIXED:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ nk_chart_add_slot_colored(ctx, NK_CHART_COLUMN, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, 0.0f, 1.0f);
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)fabs(cos(id)), 1);
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ }
+ nk_group_end(ctx);
+ } else nk_style_pop_vec2(ctx);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Simple", NK_MINIMIZED))
+ {
+ nk_layout_row_dynamic(ctx, 300, 2);
+ if (nk_group_begin(ctx, "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, "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_group_end(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Complex", NK_MINIMIZED))
+ {
+ int i;
+ 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, "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, "Group_top", NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(160,250,150,250));
+ if (nk_group_begin(ctx, "Group_buttom", NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(320,0,150,150));
+ if (nk_group_begin(ctx, "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, "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, "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;
+
+ 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, "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_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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, "center", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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, "right", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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_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, "top", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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, "middle", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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, "bottom", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ 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, "Overview");
+}
+
diff --git a/nuklear/demo/sdl_opengl2/Makefile b/nuklear/demo/sdl_opengl2/Makefile
new file mode 100644
index 0000000..2c85a6e
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lSDL2 -framework OpenGL -lm
+ else
+ LIBS = -lSDL2 -lGL -lm -lGLU
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/sdl_opengl2/main.c b/nuklear/demo/sdl_opengl2/main.c
new file mode 100644
index 0000000..0d96551
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/main.c
@@ -0,0 +1,181 @@
+/* nuklear - v1.17 - 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 <limits.h>
+#include <time.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SDL_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sdl_gl2.h"
+
+#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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(int argc, char* argv[])
+{
+ /* 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_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ win = SDL_CreateWindow("Demo",
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);
+ glContext = SDL_GL_CreateContext(win);
+ SDL_GetWindowSize(win, &win_width, &win_height);
+
+ /* GUI */
+ ctx = nk_sdl_init(win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_sdl_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 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_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &roboto->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ 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 */
+ if (nk_begin(ctx, "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"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(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]);
+ /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ 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;
+}
+
diff --git a/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h b/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h
new file mode 100644
index 0000000..45c5970
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h
@@ -0,0 +1,342 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GL2_H_
+#define NK_SDL_GL2_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 int 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);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GL2_IMPLEMENTATION
+
+struct nk_sdl_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+struct nk_sdl_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_sdl {
+ SDL_Window *win;
+ struct nk_sdl_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sdl;
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ 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_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_sdl_device *dev = &sdl.ogl;
+ int width, height;
+ int display_width, display_height;
+ struct nk_vec2 scale;
+
+ SDL_GetWindowSize(sdl.win, &width, &height);
+ SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)display_width,(GLsizei)display_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_sdl_vertex);
+ size_t vp = offsetof(struct nk_sdl_vertex, position);
+ size_t vt = offsetof(struct nk_sdl_vertex, uv);
+ size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill converting configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sdl_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ 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 * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&sdl.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+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 = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ SDL_SetClipboardText(str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+ sdl.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_buffer_init_default(&sdl.ogl.cmds);
+ return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&sdl.atlas);
+ nk_font_atlas_begin(&sdl.atlas);
+ *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_sdl_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&sdl.atlas, nk_handle_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 int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+ struct nk_context *ctx = &sdl.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ SDL_SetRelativeMouseMode(SDL_TRUE);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ SDL_SetRelativeMouseMode(SDL_FALSE);
+ SDL_WarpMouseInWindow(sdl.win, x, y);
+ ctx->input.mouse.ungrab = 0;
+ }
+ 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);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (sym == SDLK_END) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if (sym == SDLK_PAGEDOWN) {
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ } else if (sym == SDLK_PAGEUP) {
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, 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_UP)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if (sym == SDLK_DOWN)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ 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 return 0;
+ return 1;
+ } 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 return 0;
+ return 1;
+ } else if (evt->type == SDL_MOUSEMOTION) {
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ nk_input_scroll(ctx,(float)evt->wheel.y);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ nk_font_atlas_clear(&sdl.atlas);
+ nk_free(&sdl.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif
diff --git a/nuklear/demo/sdl_opengl3/Makefile b/nuklear/demo/sdl_opengl3/Makefile
new file mode 100644
index 0000000..4b8ccf4
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lSDL2 -framework OpenGL -lm -lGLEW
+ else
+ LIBS = -lSDL2 -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/sdl_opengl3/main.c b/nuklear/demo/sdl_opengl3/main.c
new file mode 100644
index 0000000..aee4f82
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/main.c
@@ -0,0 +1,195 @@
+/* nuklear - v1.17 - 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 <limits.h>
+#include <time.h>
+
+#include <GL/glew.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SDL_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sdl_gl3.h"
+
+#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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(int argc, char* argv[])
+{
+ /* 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_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+ SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
+ SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
+ SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ 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|SDL_WINDOW_ALLOW_HIGHDPI);
+ 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 */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_sdl_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 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_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &roboto->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ 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 */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ 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, "FILE", NK_TEXT_LEFT, nk_vec2(120, 200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_menu_item_label(ctx, "OPEN", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "CLOSE", NK_TEXT_LEFT);
+ nk_menu_end(ctx);
+ }
+ nk_layout_row_push(ctx, 45);
+ if (nk_menu_begin_label(ctx, "EDIT", NK_TEXT_LEFT, nk_vec2(120, 200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_menu_item_label(ctx, "COPY", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "CUT", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "PASTE", NK_TEXT_LEFT);
+ nk_menu_end(ctx);
+ }
+ nk_layout_row_end(ctx);
+ nk_menubar_end(ctx);
+
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(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]);
+ /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ 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;
+}
+
diff --git a/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h b/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h
new file mode 100644
index 0000000..17c0899
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h
@@ -0,0 +1,437 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GL3_H_
+#define NK_SDL_GL3_H_
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.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 int 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
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GL3_IMPLEMENTATION
+
+#include <string.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;
+};
+
+struct nk_sdl_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_sdl {
+ SDL_Window *win;
+ struct nk_sdl_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sdl;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+NK_API void
+nk_sdl_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_sdl_vertex);
+ size_t vp = offsetof(struct nk_sdl_vertex, position);
+ size_t vt = offsetof(struct nk_sdl_vertex, uv);
+ size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+ 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;
+ int display_width, display_height;
+ struct nk_vec2 scale;
+ 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);
+ SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* setup global state */
+ glViewport(0,0,display_width,display_height);
+ 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 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sdl_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
+ nk_buffer_init_fixed(&ebuf, elements, (nk_size)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 * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&sdl.ctx);
+ }
+
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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 = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ SDL_SetClipboardText(str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+ sdl.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 int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+ struct nk_context *ctx = &sdl.ctx;
+ 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);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (sym == SDLK_END) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if (sym == SDLK_PAGEDOWN) {
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ } else if (sym == SDLK_PAGEUP) {
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, 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_UP)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if (sym == SDLK_DOWN)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ 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 return 0;
+ return 1;
+ } 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);
+ return 1;
+ } else if (evt->type == SDL_MOUSEMOTION) {
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ nk_input_scroll(ctx,(float)evt->wheel.y);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ nk_font_atlas_clear(&sdl.atlas);
+ nk_free(&sdl.ctx);
+ nk_sdl_device_destroy();
+ memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif
diff --git a/nuklear/demo/style.c b/nuklear/demo/style.c
new file mode 100644
index 0000000..8cea152
--- /dev/null
+++ b/nuklear/demo/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);
+ }
+}
+
+
diff --git a/nuklear/demo/x11/Makefile b/nuklear/demo/x11/Makefile
new file mode 100644
index 0000000..0570089
--- /dev/null
+++ b/nuklear/demo/x11/Makefile
@@ -0,0 +1,13 @@
+# Install
+BIN = zahnrad
+
+# Flags
+CFLAGS = -std=c89 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) -lX11 -lm
diff --git a/nuklear/demo/x11/main.c b/nuklear/demo/x11/main.c
new file mode 100644
index 0000000..8f4b12c
--- /dev/null
+++ b/nuklear/demo/x11/main.c
@@ -0,0 +1,203 @@
+/* nuklear - v1.17 - public domain */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_XLIB_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_xlib.h"
+
+#define DTIME 20
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#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])
+
+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));
+}
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+#include "../overview.c"
+#include "../node_editor.c"
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+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);
+ if (!xw.dpy) die("Could not open a display; perhaps $DISPLAY is not set?");
+
+ 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);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ 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 */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ 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"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ overview(ctx);
+ node_editor(ctx);
+ /* ----------------------------------------- */
+
+ /* 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;
+}
+
diff --git a/nuklear/demo/x11/nuklear_xlib.h b/nuklear/demo/x11/nuklear_xlib.h
new file mode 100644
index 0000000..df66d78
--- /dev/null
+++ b/nuklear/demo/x11/nuklear_xlib.h
@@ -0,0 +1,693 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_H_
+#define NK_XLIB_H_
+
+#include <X11/Xlib.h>
+/* Font */
+typedef struct XFont XFont;
+NK_API XFont* nk_xfont_create(Display *dpy, const char *name);
+NK_API void nk_xfont_del(Display *dpy, XFont *font);
+
+NK_API struct nk_context* nk_xlib_init(XFont *font, Display *dpy, int screen, Window root, unsigned int w, unsigned int h);
+NK_API int 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);
+NK_API void nk_xlib_set_font(XFont *font);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_IMPLEMENTATION
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+typedef struct XSurface XSurface;
+struct XFont {
+ int ascent;
+ int descent;
+ int height;
+ XFontSet set;
+ XFontStruct *xfont;
+ struct nk_user_font handle;
+};
+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;
+ Cursor cursor;
+ Display *dpy;
+ Window root;
+} 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
+nk_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(int screen, unsigned int w, unsigned int h)
+{
+ XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));
+ surface->w = w;
+ surface->h = h;
+ surface->dpy = xlib.dpy;
+ surface->screen = screen;
+ surface->root = xlib.root;
+ surface->gc = XCreateGC(xlib.dpy, xlib.root, 0, NULL);
+ XSetLineAttributes(xlib.dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
+ surface->drawable = XCreatePixmap(xlib.dpy, xlib.root, w, h,
+ (unsigned int)DefaultDepth(xlib.dpy, screen));
+ 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 = nk_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 = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ if (r == 0) {
+ XDrawRectangle(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+hc);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc);
+
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+ (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y,
+ (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+ (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+ XDrawArc(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 = nk_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 = nk_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 = nk_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 = nk_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 = nk_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 = nk_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 = nk_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 = nk_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 = nk_color_from_byte(&cbg.r);
+ unsigned long fg = nk_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 = &xfont->handle;
+ font->userdata = nk_handle_ptr(xfont);
+ font->height = (float)xfont->height;
+ font->width = nk_xfont_get_text_width;
+ xlib.dpy = dpy;
+ xlib.root = root;
+
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1);
+ if (blank == None) return 0;
+ xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ xlib.surf = nk_xsurf_create(screen, 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 = &xfont->handle;
+ 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 int
+nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
+{
+ struct nk_context *ctx = &xlib.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(xlib.dpy, xlib.root, xlib.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0,
+ (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);
+ XUndefineCursor(xlib.dpy, xlib.root);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ 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_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_Escape) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } 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 (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } 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 return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(xlib.dpy, None, xlib.surf->root, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } 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);
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API void
+nk_xlib_shutdown(void)
+{
+ nk_xsurf_del(xlib.surf);
+ nk_free(&xlib.ctx);
+ XFreeCursor(xlib.dpy, xlib.cursor);
+ nk_memset(&xlib, 0, sizeof(xlib));
+}
+
+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, nk_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);
+}
+#endif
diff --git a/nuklear/demo/x11_opengl2/Makefile b/nuklear/demo/x11_opengl2/Makefile
new file mode 100644
index 0000000..1173b6c
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/Makefile
@@ -0,0 +1,26 @@
+# Install
+BIN = demo
+
+# Compiler
+CC = clang
+DCC = gcc
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.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
diff --git a/nuklear/demo/x11_opengl2/main.c b/nuklear/demo/x11_opengl2/main.c
new file mode 100644
index 0000000..cfe5604
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/main.c
@@ -0,0 +1,320 @@
+/* nuklear - v1.17 - 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/glx.h>
+#include <GL/glxext.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_XLIB_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_xlib_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+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 int gl_error_handler(Display *dpy, XErrorEvent *ev)
+{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+
+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 int
+has_extension(const char *string, const char *ext)
+{
+ const char *start, *where, *term;
+ where = strchr(ext, ' ');
+ if (where || *ext == '\0')
+ return FALSE;
+
+ for (start = string;;) {
+ 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;
+}
+
+int main(int argc, char **argv)
+{
+ /* Platform */
+ int running = 1;
+ struct XWindow win;
+ GLXContext glContext;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ memset(&win, 0, sizeof(win));
+ 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");
+ }
+ {
+ /* 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;
+ fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
+ if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
+ {
+ /* pick framebuffer with most samples per pixel */
+ int i;
+ 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);
+ 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);
+ }
+ }
+ {
+ /* create window */
+ 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;
+ 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, "Demo");
+ XMapWindow(win.dpy, win.win);
+ }
+ {
+ /* create opengl context */
+ typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+ int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
+ const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
+ glxCreateContext create_context = (glxCreateContext)
+ glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
+
+ gl_err = FALSE;
+ if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
+ fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
+ fprintf(stdout, "[X11]: ... using old-style GLX context\n");
+ glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
+ } else {
+ GLint attr[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ None
+ };
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ XSync(win.dpy, False);
+ if (gl_err || !glContext) {
+ /* 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");
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ }
+ }
+ XSync(win.dpy, False);
+ XSetErrorHandler(old_handler);
+ if (gl_err || !glContext)
+ die("[X11]: Failed to create an OpenGL context\n");
+ glXMakeCurrent(win.dpy, win.win, glContext);
+ }
+
+ ctx = nk_x11_init(win.dpy, win.win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_x11_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_x11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ nk_input_begin(ctx);
+ while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)){
+ if (XFilterEvent(&evt, win.win)) continue;
+ nk_x11_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ 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"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ XGetWindowAttributes(win.dpy, win.win, &win.attr);
+ glViewport(0, 0, win.width, win.height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glXSwapBuffers(win.dpy, win.win);}
+ }
+
+ nk_x11_shutdown();
+ glXMakeCurrent(win.dpy, 0, 0);
+ glXDestroyContext(win.dpy, glContext);
+ XUnmapWindow(win.dpy, win.win);
+ XFreeColormap(win.dpy, win.cmap);
+ XDestroyWindow(win.dpy, win.win);
+ XCloseDisplay(win.dpy);
+ return 0;
+
+}
diff --git a/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h b/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h
new file mode 100644
index 0000000..a814455
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h
@@ -0,0 +1,357 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_GL3_H_
+#define NK_XLIB_GL3_H_
+
+#include <X11/Xlib.h>
+NK_API struct nk_context* nk_x11_init(Display *dpy, Window win);
+NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_x11_font_stash_end(void);
+NK_API int nk_x11_handle_event(XEvent *evt);
+NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_x11_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_GL2_IMPLEMENTATION
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#include <GL/gl.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+struct nk_x11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct nk_x11_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+static struct nk_x11 {
+ struct nk_x11_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ Cursor cursor;
+ Display *dpy;
+ Window win;
+} x11;
+
+NK_INTERN void
+nk_x11_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_x11_device *dev = &x11.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_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_x11_device *dev = &x11.ogl;
+ int width, height;
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(x11.dpy, x11.win, &attr);
+ width = attr.width;
+ height = attr.height;
+
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)width,(GLsizei)height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_x11_vertex);
+ size_t vp = offsetof(struct nk_x11_vertex, position);
+ size_t vt = offsetof(struct nk_x11_vertex, uv);
+ size_t vc = offsetof(struct nk_x11_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_x11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((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(&x11.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+
+}
+
+NK_API void
+nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&x11.atlas);
+ nk_font_atlas_begin(&x11.atlas);
+ *atlas = &x11.atlas;
+}
+
+NK_API void
+nk_x11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_x11_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
+ if (x11.atlas.default_font)
+ nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
+}
+
+NK_API int
+nk_x11_handle_event(XEvent *evt)
+{
+ struct nk_context *ctx = &x11.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(x11.dpy, x11.win, x11.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
+ (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ XUndefineCursor(x11.dpy, x11.win);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ if (evt->type == KeyPress || evt->type == KeyRelease)
+ {
+ /* Key handler */
+ int ret, down = (evt->type == KeyPress);
+ KeySym *code = XGetKeyboardMapping(x11.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_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } 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 (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } 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 return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API struct nk_context*
+nk_x11_init(Display *dpy, Window win)
+{
+ x11.dpy = dpy;
+ x11.win = win;
+
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
+ if (blank == None) return 0;
+ x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ nk_buffer_init_default(&x11.ogl.cmds);
+ nk_init_default(&x11.ctx, 0);
+ return &x11.ctx;
+}
+
+NK_API void
+nk_x11_shutdown(void)
+{
+ struct nk_x11_device *dev = &x11.ogl;
+ nk_font_atlas_clear(&x11.atlas);
+ nk_free(&x11.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ XFreeCursor(x11.dpy, x11.cursor);
+ memset(&x11, 0, sizeof(x11));
+}
+
+#endif
diff --git a/nuklear/demo/x11_opengl3/Makefile b/nuklear/demo/x11_opengl3/Makefile
new file mode 100644
index 0000000..1173b6c
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/Makefile
@@ -0,0 +1,26 @@
+# Install
+BIN = demo
+
+# Compiler
+CC = clang
+DCC = gcc
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.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
diff --git a/nuklear/demo/x11_opengl3/main.c b/nuklear/demo/x11_opengl3/main.c
new file mode 100644
index 0000000..cd026f9
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/main.c
@@ -0,0 +1,317 @@
+/* nuklear - v1.17 - 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>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_XLIB_GL3_IMPLEMENTATION
+#define NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include "../../nuklear.h"
+#include "nuklear_xlib_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 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])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+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 int gl_error_handler(Display *dpy, XErrorEvent *ev)
+{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+
+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 int
+has_extension(const char *string, const char *ext)
+{
+ const char *start, *where, *term;
+ where = strchr(ext, ' ');
+ if (where || *ext == '\0')
+ return FALSE;
+
+ for (start = string;;) {
+ 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;
+}
+
+int main(int argc, char **argv)
+{
+ /* Platform */
+ int running = 1;
+ struct XWindow win;
+ GLXContext glContext;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ memset(&win, 0, sizeof(win));
+ 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");
+ }
+ {
+ /* 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;
+ fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
+ if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
+ {
+ /* pick framebuffer with most samples per pixel */
+ int i;
+ 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);
+ 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);
+ }
+ }
+ {
+ /* create window */
+ 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;
+ 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, "Demo");
+ XMapWindow(win.dpy, win.win);
+ }
+ {
+ /* create opengl context */
+ typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+ int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
+ const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
+ glxCreateContext create_context = (glxCreateContext)
+ glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
+
+ gl_err = FALSE;
+ if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
+ fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
+ fprintf(stdout, "[X11]: ... using old-style GLX context\n");
+ glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
+ } else {
+ GLint attr[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ None
+ };
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ XSync(win.dpy, False);
+ if (gl_err || !glContext) {
+ /* 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");
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ }
+ }
+ XSync(win.dpy, False);
+ XSetErrorHandler(old_handler);
+ if (gl_err || !glContext)
+ die("[X11]: Failed to create an OpenGL context\n");
+ glXMakeCurrent(win.dpy, win.win, glContext);
+ }
+
+ ctx = nk_x11_init(win.dpy, win.win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ {struct nk_font_atlas *atlas;
+ nk_x11_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_x11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ nk_input_begin(ctx);
+ while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)){
+ if (XFilterEvent(&evt, win.win)) continue;
+ nk_x11_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ 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"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),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);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ XGetWindowAttributes(win.dpy, win.win, &win.attr);
+ glViewport(0, 0, win.width, win.height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glXSwapBuffers(win.dpy, win.win);}
+ }
+
+ nk_x11_shutdown();
+ glXMakeCurrent(win.dpy, 0, 0);
+ glXDestroyContext(win.dpy, glContext);
+ XUnmapWindow(win.dpy, win.win);
+ XFreeColormap(win.dpy, win.cmap);
+ XDestroyWindow(win.dpy, win.win);
+ XCloseDisplay(win.dpy);
+ return 0;
+
+}
diff --git a/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h b/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h
new file mode 100644
index 0000000..b0f56b9
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h
@@ -0,0 +1,725 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_GL3_H_
+#define NK_XLIB_GL3_H_
+
+#include <X11/Xlib.h>
+NK_API struct nk_context* nk_x11_init(Display *dpy, Window win);
+NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_x11_font_stash_end(void);
+NK_API int nk_x11_handle_event(XEvent *evt);
+NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_x11_shutdown(void);
+NK_API int nk_x11_device_create(void);
+NK_API void nk_x11_device_destroy(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_GL3_IMPLEMENTATION
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include <GL/glxext.h>
+
+/* GL_ARB_vertex_buffer_object */
+typedef void(*nkglGenBuffers)(GLsizei, GLuint*);
+typedef void(*nkglBindBuffer)(GLenum, GLuint);
+typedef void(*nkglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
+typedef void(*nkglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);
+typedef void*(*nkglMapBuffer)(GLenum, GLenum);
+typedef GLboolean(*nkglUnmapBuffer)(GLenum);
+typedef void(*nkglDeleteBuffers)(GLsizei, GLuint*);
+/* GL_ARB_vertex_array_object */
+typedef void (*nkglGenVertexArrays)(GLsizei, GLuint*);
+typedef void (*nkglBindVertexArray)(GLuint);
+typedef void (*nkglDeleteVertexArrays)(GLsizei, const GLuint*);
+/* GL_ARB_vertex_program / GL_ARB_fragment_program */
+typedef void(*nkglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
+typedef void(*nkglEnableVertexAttribArray)(GLuint);
+typedef void(*nkglDisableVertexAttribArray)(GLuint);
+/* GL_ARB_framebuffer_object */
+typedef void(*nkglGenerateMipmap)(GLenum target);
+/* GLSL/OpenGL 2.0 core */
+typedef GLuint(*nkglCreateShader)(GLenum);
+typedef void(*nkglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);
+typedef void(*nkglCompileShader)(GLuint);
+typedef void(*nkglGetShaderiv)(GLuint, GLenum, GLint*);
+typedef void(*nkglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
+typedef void(*nkglDeleteShader)(GLuint);
+typedef GLuint(*nkglCreateProgram)(void);
+typedef void(*nkglAttachShader)(GLuint, GLuint);
+typedef void(*nkglDetachShader)(GLuint, GLuint);
+typedef void(*nkglLinkProgram)(GLuint);
+typedef void(*nkglUseProgram)(GLuint);
+typedef void(*nkglGetProgramiv)(GLuint, GLenum, GLint*);
+typedef void(*nkglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
+typedef void(*nkglDeleteProgram)(GLuint);
+typedef GLint(*nkglGetUniformLocation)(GLuint, const GLchar*);
+typedef GLint(*nkglGetAttribLocation)(GLuint, const GLchar*);
+typedef void(*nkglUniform1i)(GLint, GLint);
+typedef void(*nkglUniform1f)(GLint, GLfloat);
+typedef void(*nkglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void(*nkglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);
+
+static nkglGenBuffers glGenBuffers;
+static nkglBindBuffer glBindBuffer;
+static nkglBufferData glBufferData;
+static nkglBufferSubData glBufferSubData;
+static nkglMapBuffer glMapBuffer;
+static nkglUnmapBuffer glUnmapBuffer;
+static nkglDeleteBuffers glDeleteBuffers;
+static nkglGenVertexArrays glGenVertexArrays;
+static nkglBindVertexArray glBindVertexArray;
+static nkglDeleteVertexArrays glDeleteVertexArrays;
+static nkglVertexAttribPointer glVertexAttribPointer;
+static nkglEnableVertexAttribArray glEnableVertexAttribArray;
+static nkglDisableVertexAttribArray glDisableVertexAttribArray;
+static nkglGenerateMipmap glGenerateMipmap;
+static nkglCreateShader glCreateShader;
+static nkglShaderSource glShaderSource;
+static nkglCompileShader glCompileShader;
+static nkglGetShaderiv glGetShaderiv;
+static nkglGetShaderInfoLog glGetShaderInfoLog;
+static nkglDeleteShader glDeleteShader;
+static nkglCreateProgram glCreateProgram;
+static nkglAttachShader glAttachShader;
+static nkglDetachShader glDetachShader;
+static nkglLinkProgram glLinkProgram;
+static nkglUseProgram glUseProgram;
+static nkglGetProgramiv glGetProgramiv;
+static nkglGetProgramInfoLog glGetProgramInfoLog;
+static nkglDeleteProgram glDeleteProgram;
+static nkglGetUniformLocation glGetUniformLocation;
+static nkglGetAttribLocation glGetAttribLocation;
+static nkglUniform1i glUniform1i;
+static nkglUniform1f glUniform1f;
+static nkglUniformMatrix3fv glUniformMatrix3fv;
+static nkglUniformMatrix4fv glUniformMatrix4fv;
+
+enum graphics_card_vendors {
+ VENDOR_UNKNOWN,
+ VENDOR_NVIDIA,
+ VENDOR_AMD,
+ VENDOR_INTEL
+};
+
+struct opengl_info {
+ /* 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;
+};
+#endif
+
+struct nk_x11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct nk_x11_device {
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+ struct opengl_info info;
+#endif
+ 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_x11 {
+ struct nk_x11_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ Cursor cursor;
+ Display *dpy;
+ Window win;
+} x11;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include <GL/glx.h>
+
+NK_INTERN int
+nk_x11_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;
+}
+
+NK_INTERN int
+nk_x11_check_extension(struct opengl_info *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) (nk##name)nk_gl_ext(#name)
+NK_INTERN __GLXextFuncPtr
+nk_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;
+}
+
+NK_INTERN int
+nk_load_opengl(struct opengl_info *gl)
+{
+ 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) {
+ fprintf(stderr, "[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n");
+ return 0;
+ }
+
+ 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 (!nk_x11_stricmpn(gl->vendor_str, "ATI", 4) ||
+ !nk_x11_stricmpn(gl->vendor_str, "AMD", 4))
+ gl->vendor = VENDOR_AMD;
+ else if (!nk_x11_stricmpn(gl->vendor_str, "NVIDIA", 6))
+ gl->vendor = VENDOR_NVIDIA;
+ else if (!nk_x11_stricmpn(gl->vendor_str, "Intel", 5))
+ gl->vendor = VENDOR_INTEL;
+ else gl->vendor = VENDOR_UNKNOWN;
+
+ /* Extensions */
+ 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 = nk_x11_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 = nk_x11_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 = nk_x11_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 = nk_x11_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;
+ }
+ return !failed;
+}
+#endif
+
+NK_API int
+nk_x11_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_x11_device *dev = &x11.ogl;
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+ if (!nk_load_opengl(&dev->info)) return 0;
+#endif
+ 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_x11_vertex);
+ size_t vp = offsetof(struct nk_x11_vertex, position);
+ size_t vt = offsetof(struct nk_x11_vertex, uv);
+ size_t vc = offsetof(struct nk_x11_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);
+ return 1;
+}
+
+NK_INTERN void
+nk_x11_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_x11_device *dev = &x11.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_x11_device_destroy(void)
+{
+ struct nk_x11_device *dev = &x11.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_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ int width, height;
+ XWindowAttributes attr;
+ struct nk_x11_device *dev = &x11.ogl;
+ 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},
+ };
+ XGetWindowAttributes(x11.dpy, x11.win, &attr);
+ width = attr.width;
+ height = attr.height;
+
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* 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]);
+ glViewport(0,0,(GLsizei)width,(GLsizei)height);
+ {
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_x11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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(&x11.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, &x11.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((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(&x11.ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+NK_API void
+nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&x11.atlas);
+ nk_font_atlas_begin(&x11.atlas);
+ *atlas = &x11.atlas;
+}
+
+NK_API void
+nk_x11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_x11_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
+ if (x11.atlas.default_font)
+ nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
+}
+
+NK_API int
+nk_x11_handle_event(XEvent *evt)
+{
+ struct nk_context *ctx = &x11.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(x11.dpy, x11.win, x11.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
+ (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ XUndefineCursor(x11.dpy, x11.win);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ if (evt->type == KeyPress || evt->type == KeyRelease)
+ {
+ /* Key handler */
+ int ret, down = (evt->type == KeyPress);
+ KeySym *code = XGetKeyboardMapping(x11.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_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } 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 (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } 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 return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API struct nk_context*
+nk_x11_init(Display *dpy, Window win)
+{
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+ if (!nk_x11_device_create()) return 0;
+
+ x11.dpy = dpy;
+ x11.win = win;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
+ if (blank == None) return 0;
+ x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ nk_init_default(&x11.ctx, 0);
+ return &x11.ctx;
+}
+
+NK_API void
+nk_x11_shutdown(void)
+{
+ nk_font_atlas_clear(&x11.atlas);
+ nk_free(&x11.ctx);
+ nk_x11_device_destroy();
+ XFreeCursor(x11.dpy, x11.cursor);
+ memset(&x11, 0, sizeof(x11));
+}
+
+#endif
diff --git a/nuklear/example/Makefile b/nuklear/example/Makefile
new file mode 100644
index 0000000..22829a2
--- /dev/null
+++ b/nuklear/example/Makefile
@@ -0,0 +1,41 @@
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+LIBS :=
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+ LIBS := -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS := -lglfw3 -framework OpenGL -lm -lGLEW -L/usr/local/lib
+ CFLAGS += -I/usr/local/include
+ else
+ LIBS := -lglfw -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+all: generate file_browser extended canvas skinning
+
+generate: clean
+ifeq ($(OS),Windows_NT)
+ @mkdir bin 2> nul || exit 0
+else
+ @mkdir -p bin
+endif
+
+clean:
+ @rm -rf bin
+
+file_browser: generate
+ $(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS)
+
+extended: generate
+ $(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS)
+
+canvas: generate
+ $(CC) $(CFLAGS) -o bin/canvas canvas.c $(LIBS)
+
+skinning: generate
+ $(CC) $(CFLAGS) -o bin/skinning skinning.c $(LIBS)
+
diff --git a/nuklear/example/canvas.c b/nuklear/example/canvas.c
new file mode 100644
index 0000000..c5f5634
--- /dev/null
+++ b/nuklear/example/canvas.c
@@ -0,0 +1,489 @@
+/* nuklear - v1.05 - 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 <GLFW/glfw3.h>
+
+#define NK_PRIVATE
+#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])
+
+#define NK_SHADER_VERSION "#version 150\n"
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+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 =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_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)
+{
+ 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;
+
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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),
+ (GLint)((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);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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);}
+
+static void
+pump_input(struct nk_context *ctx, GLFWwindow *win)
+{
+ 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) == GLFW_PRESS) {
+ 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);
+}
+
+struct nk_canvas {
+ struct nk_command_buffer *painter;
+ struct nk_vec2 item_spacing;
+ struct nk_vec2 panel_padding;
+ struct nk_style_item window_background;
+};
+
+static void
+canvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags,
+ int x, int y, int width, int height, struct nk_color background_color)
+{
+ /* save style properties which will be overwritten */
+ canvas->panel_padding = ctx->style.window.padding;
+ canvas->item_spacing = ctx->style.window.spacing;
+ canvas->window_background = ctx->style.window.fixed_background;
+
+ /* use the complete window space and set background */
+ ctx->style.window.spacing = nk_vec2(0,0);
+ ctx->style.window.padding = nk_vec2(0,0);
+ ctx->style.window.fixed_background = nk_style_item_color(background_color);
+
+ /* create/update window and set position + size */
+ flags = flags & ~NK_WINDOW_DYNAMIC;
+ nk_begin(ctx, "Window", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags);
+ nk_window_set_bounds(ctx, nk_rect(x, y, width, height));
+
+ /* allocate the complete window space for drawing */
+ {struct nk_rect total_space;
+ total_space = nk_window_get_content_region(ctx);
+ nk_layout_row_dynamic(ctx, total_space.h, 1);
+ nk_widget(&total_space, ctx);
+ canvas->painter = nk_window_get_canvas(ctx);}
+}
+
+static void
+canvas_end(struct nk_context *ctx, struct nk_canvas *canvas)
+{
+ nk_end(ctx);
+ ctx->style.window.spacing = canvas->panel_padding;
+ ctx->style.window.padding = canvas->item_spacing;
+ ctx->style.window.fixed_background = canvas->window_background;
+}
+
+int main(int argc, char *argv[])
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ 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);
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwSetWindowUserPointer(win, &ctx);
+ glfwSetCharCallback(win, text_input);
+ glfwSetScrollCallback(win, scroll_input);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* 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;
+ struct nk_font *font;
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ font = nk_font_atlas_add_default(&atlas, 13, 0);
+ 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);
+
+ glEnable(GL_TEXTURE_2D);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* input */
+ pump_input(&ctx, win);
+
+ /* draw */
+ {struct nk_canvas canvas;
+ canvas_begin(&ctx, &canvas, 0, 0, 0, width, height, nk_rgb(250,250,250));
+ {
+ nk_fill_rect(canvas.painter, nk_rect(15,15,210,210), 5, nk_rgb(247, 230, 154));
+ nk_fill_rect(canvas.painter, nk_rect(20,20,200,200), 5, nk_rgb(188, 174, 118));
+ nk_draw_text(canvas.painter, nk_rect(30, 30, 150, 20), "Text to draw", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0));
+ nk_fill_rect(canvas.painter, nk_rect(250,20,100,100), 0, nk_rgb(0,0,255));
+ nk_fill_circle(canvas.painter, nk_rect(20,250,100,100), nk_rgb(255,0,0));
+ nk_fill_triangle(canvas.painter, 250, 250, 350, 250, 300, 350, nk_rgb(0,255,0));
+ nk_fill_arc(canvas.painter, 300, 180, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0));
+
+ {float points[12];
+ points[0] = 200; points[1] = 250;
+ points[2] = 250; points[3] = 350;
+ points[4] = 225; points[5] = 350;
+ points[6] = 200; points[7] = 300;
+ points[8] = 175; points[9] = 350;
+ points[10] = 150; points[11] = 350;
+ nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));}
+
+ nk_stroke_line(canvas.painter, 15, 10, 200, 10, 2.0f, nk_rgb(189,45,75));
+ nk_stroke_rect(canvas.painter, nk_rect(370, 20, 100, 100), 10, 3, nk_rgb(0,0,255));
+ nk_stroke_curve(canvas.painter, 380, 200, 405, 270, 455, 120, 480, 200, 2, nk_rgb(0,150,220));
+ nk_stroke_circle(canvas.painter, nk_rect(20, 370, 100, 100), 5, nk_rgb(0,255,120));
+ nk_stroke_triangle(canvas.painter, 370, 250, 470, 250, 420, 350, 6, nk_rgb(255,0,143));
+ }
+ canvas_end(&ctx, &canvas);}
+
+ /* 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;
+}
+
diff --git a/nuklear/example/extended.c b/nuklear/example/extended.c
new file mode 100644
index 0000000..e555d65
--- /dev/null
+++ b/nuklear/example/extended.c
@@ -0,0 +1,906 @@
+/* nuklear - v1.05 - 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 <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])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+struct media {
+ struct nk_font *font_14;
+ struct nk_font *font_18;
+ struct nk_font *font_20;
+ struct nk_font *font_22;
+
+ 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_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);
+ ctx->style.window.spacing = nk_vec2(0,0);
+ ctx->style.window.padding = nk_vec2(0,0);
+
+ if (nk_popup_begin(ctx, 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)))
+ {
+ int i = 0;
+ struct nk_command_buffer* out = nk_window_get_canvas(ctx);
+ const struct nk_input *in = &ctx->input;
+
+ total_space = nk_window_get_content_region(ctx);
+ ctx->style.window.spacing = nk_vec2(4,4);
+ ctx->style.window.padding = nk_vec2(8,8);
+ nk_layout_row_dynamic(ctx, total_space.h, 1);
+ 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));
+
+ /* separator 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], nk_rgb(255,255,255));
+ 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_rgb(255,255,255));
+ }
+ nk_layout_space_end(ctx);
+ if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT)) {
+ nk_popup_close(ctx);
+ ret = active_item;
+ }
+ } else ret = -2;
+ ctx->style.window.spacing = nk_vec2(4,4);
+ ctx->style.window.padding = nk_vec2(8,8);
+ nk_popup_end(ctx);
+
+ ctx->style.window.fixed_background = background;
+ ctx->style.window.border_color = border;
+ return ret;
+}
+
+/* ===============================================================
+ *
+ * GRID
+ *
+ * ===============================================================*/
+static void
+grid_demo(struct nk_context *ctx, struct media *media)
+{
+ 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;
+
+ int i;
+ nk_style_set_font(ctx, &media->font_20->handle);
+ if (nk_begin(ctx, "Grid Demo", nk_rect(600, 350, 275, 250),
+ NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|
+ NK_WINDOW_NO_SCROLLBAR))
+ {
+ nk_style_set_font(ctx, &media->font_18->handle);
+ 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, "Hexadecimal:", 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, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {
+ nk_layout_row_dynamic(ctx, 25, 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);
+ nk_style_set_font(ctx, &media->font_14->handle);
+}
+
+/* ===============================================================
+ *
+ * BUTTON DEMO
+ *
+ * ===============================================================*/
+static void
+ui_header(struct nk_context *ctx, struct media *media, const char *title)
+{
+ nk_style_set_font(ctx, &media->font_18->handle);
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, title, NK_TEXT_LEFT);
+}
+
+static void
+ui_widget(struct nk_context *ctx, struct media *media, float height)
+{
+ static const float ratio[] = {0.15f, 0.85f};
+ nk_style_set_font(ctx, &media->font_22->handle);
+ nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);
+ nk_spacing(ctx, 1);
+}
+
+static void
+ui_widget_centered(struct nk_context *ctx, struct media *media, float height)
+{
+ static const float ratio[] = {0.15f, 0.50f, 0.35f};
+ nk_style_set_font(ctx, &media->font_22->handle);
+ nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio);
+ nk_spacing(ctx, 1);
+}
+
+static void
+button_demo(struct nk_context *ctx, struct media *media)
+{
+ static int option = 1;
+ static int toggle0 = 1;
+ static int toggle1 = 0;
+ static int toggle2 = 1;
+
+ nk_style_set_font(ctx, &media->font_20->handle);
+ nk_begin(ctx, "Button Demo", nk_rect(50,50,255,610),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);
+
+ /*------------------------------------------------
+ * MENU
+ *------------------------------------------------*/
+ nk_menubar_begin(ctx);
+ {
+ /* toolbar */
+ nk_layout_row_static(ctx, 40, 40, 4);
+ if (nk_menu_begin_image(ctx, "Music", media->play, nk_vec2(110,120)))
+ {
+ /* settings */
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_menu_item_image_label(ctx, media->play, "Play", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->stop, "Stop", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->pause, "Pause", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->next, "Next", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->prev, "Prev", NK_TEXT_RIGHT);
+ nk_menu_end(ctx);
+ }
+ nk_button_image(ctx, media->tools);
+ nk_button_image(ctx, media->cloud);
+ nk_button_image(ctx, media->pen);
+ }
+ nk_menubar_end(ctx);
+
+ /*------------------------------------------------
+ * BUTTON
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Push buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_label(ctx, "Push me"))
+ fprintf(stdout, "pushed!\n");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, media->rocket, "Styled", NK_TEXT_CENTERED))
+ fprintf(stdout, "rocket!\n");
+
+ /*------------------------------------------------
+ * REPEATER
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Repeater");
+ ui_widget(ctx, media, 35);
+ if (nk_button_label(ctx, "Press me"))
+ fprintf(stdout, "pressed!\n");
+
+ /*------------------------------------------------
+ * TOGGLE
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Toggle buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle0) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle0 = !toggle0;
+
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle1) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle1 = !toggle1;
+
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle2) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle2 = !toggle2;
+
+ /*------------------------------------------------
+ * RADIO
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Radio buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 0;
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 1;
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 2;
+
+ /*------------------------------------------------
+ * CONTEXTUAL
+ *------------------------------------------------*/
+ nk_style_set_font(ctx, &media->font_18->handle);
+ if (nk_contextual_begin(ctx, NK_WINDOW_NO_SCROLLBAR, nk_vec2(150, 300), nk_window_get_bounds(ctx))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ if (nk_contextual_item_image_label(ctx, media->copy, "Clone", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed clone!\n");
+ if (nk_contextual_item_image_label(ctx, media->del, "Delete", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed delete!\n");
+ if (nk_contextual_item_image_label(ctx, media->convert, "Convert", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed convert!\n");
+ if (nk_contextual_item_image_label(ctx, media->edit, "Edit", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed edit!\n");
+ nk_contextual_end(ctx);
+ }
+ nk_style_set_font(ctx, &media->font_14->handle);
+ nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ * BASIC DEMO
+ *
+ * ===============================================================*/
+static void
+basic_demo(struct nk_context *ctx, struct media *media)
+{
+ 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;
+ nk_style_set_font(ctx, &media->font_20->handle);
+ nk_begin(ctx, "Basic Demo", nk_rect(320, 50, 275, 610),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);
+
+ /*------------------------------------------------
+ * POPUP BUTTON
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Popup & Scrollbar & Images");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, media->dir, "Images", NK_TEXT_CENTERED))
+ image_active = !image_active;
+
+ /*------------------------------------------------
+ * SELECTED IMAGE
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Selected Image");
+ ui_widget_centered(ctx, media, 100);
+ nk_image(ctx, media->images[selected_image]);
+
+ /*------------------------------------------------
+ * IMAGE POPUP
+ *------------------------------------------------*/
+ if (image_active) {
+ struct nk_panel popup;
+ if (nk_popup_begin(ctx, 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, media->images[i])) {
+ selected_image = i;
+ image_active = 0;
+ nk_popup_close(ctx);
+ }
+ }
+ nk_popup_end(ctx);
+ }
+ }
+ /*------------------------------------------------
+ * COMBOBOX
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Combo box");
+ ui_widget(ctx, media, 40);
+ if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 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, media, 40);
+ if (nk_combo_begin_image_label(ctx, items[selected_icon], media->images[selected_icon], nk_vec2(nk_widget_width(ctx), 200))) {
+ nk_layout_row_dynamic(ctx, 35, 1);
+ for (i = 0; i < 3; ++i)
+ if (nk_combo_item_image_label(ctx, media->images[i], items[i], NK_TEXT_RIGHT))
+ selected_icon = i;
+ nk_combo_end(ctx);
+ }
+
+ /*------------------------------------------------
+ * CHECKBOX
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Checkbox");
+ ui_widget(ctx, media, 30);
+ nk_checkbox_label(ctx, "Flag 1", &check0);
+ ui_widget(ctx, media, 30);
+ nk_checkbox_label(ctx, "Flag 2", &check1);
+
+ /*------------------------------------------------
+ * PROGRESSBAR
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Progressbar");
+ ui_widget(ctx, media, 35);
+ nk_progress(ctx, &prog, 100, nk_true);
+
+ /*------------------------------------------------
+ * PIEMENU
+ *------------------------------------------------*/
+ if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT,
+ nk_window_get_bounds(ctx),nk_true)){
+ piemenu_pos = ctx->input.mouse.pos;
+ piemenu_active = 1;
+ }
+
+ if (piemenu_active) {
+ int ret = ui_piemenu(ctx, piemenu_pos, 140, &media->menu[0], 6);
+ if (ret == -2) piemenu_active = 0;
+ if (ret != -1) {
+ fprintf(stdout, "piemenu selected: %d\n", ret);
+ piemenu_active = 0;
+ }
+ }
+ nk_style_set_font(ctx, &media->font_14->handle);
+ nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+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 =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_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,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ 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;
+
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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 * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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;
+ int display_width=0, display_height=0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct media media;
+ 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);
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+
+ /* 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;
+ struct nk_font_config cfg = nk_font_config(0);
+ cfg.oversample_h = 3; cfg.oversample_v = 2;
+ /* Loading one font with different heights is only required if you want higher
+ * quality text otherwise you can just set the font height directly
+ * e.g.: ctx->style.font.height = 20. */
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ media.font_14 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 14.0f, &cfg);
+ media.font_18 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 18.0f, &cfg);
+ media.font_20 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 20.0f, &cfg);
+ media.font_22 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 22.0f, &cfg);
+ 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, &media.font_14->handle);}
+
+ /* icons */
+ glEnable(GL_TEXTURE_2D);
+ media.unchecked = icon_load("../icon/unchecked.png");
+ media.checked = icon_load("../icon/checked.png");
+ media.rocket = icon_load("../icon/rocket.png");
+ media.cloud = icon_load("../icon/cloud.png");
+ media.pen = icon_load("../icon/pen.png");
+ media.play = icon_load("../icon/play.png");
+ media.pause = icon_load("../icon/pause.png");
+ media.stop = icon_load("../icon/stop.png");
+ media.next = icon_load("../icon/next.png");
+ media.prev = icon_load("../icon/prev.png");
+ media.tools = icon_load("../icon/tools.png");
+ media.dir = icon_load("../icon/directory.png");
+ media.copy = icon_load("../icon/copy.png");
+ media.convert = icon_load("../icon/export.png");
+ media.del = icon_load("../icon/delete.png");
+ media.edit = icon_load("../icon/edit.png");
+ media.menu[0] = icon_load("../icon/home.png");
+ media.menu[1] = icon_load("../icon/phone.png");
+ media.menu[2] = icon_load("../icon/plane.png");
+ media.menu[3] = icon_load("../icon/wifi.png");
+ media.menu[4] = icon_load("../icon/settings.png");
+ media.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));
+ media.images[i] = icon_load(buffer);
+ }}
+
+ while (!glfwWindowShouldClose(win))
+ {
+ /* High DPI displays */
+ struct nk_vec2 scale;
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* 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) == GLFW_PRESS) {
+ 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, &media);
+ button_demo(&ctx, &media);
+ grid_demo(&ctx, &media);
+
+ /* Draw */
+ glViewport(0, 0, display_width, display_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
+ device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+ glfwSwapBuffers(win);
+ }
+
+ glDeleteTextures(1,(const GLuint*)&media.unchecked.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.checked.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.rocket.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.cloud.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.pen.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.play.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.pause.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.stop.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.next.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.prev.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.tools.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.dir.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.del.handle.id);
+
+ nk_font_atlas_clear(&atlas);
+ nk_free(&ctx);
+
+ device_shutdown(&device);
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/example/file_browser.c b/nuklear/example/file_browser.c
new file mode 100644
index 0000000..ece4cb8
--- /dev/null
+++ b/nuklear/example/file_browser.c
@@ -0,0 +1,910 @@
+/* nuklear - v1.05 - 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 <unistd.h>
+#include <dirent.h>
+
+#include <GL/glew.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])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+/* ===============================================================
+ *
+ * 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) {
+ void *old = results;
+ capacity = capacity * 2;
+ results = (char**)realloc(results, capacity * sizeof(char*));
+ assert(results);
+ if (!results) free(old);
+ }
+ 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 media *media = browser->media;
+ struct nk_rect total_space;
+
+ if (nk_begin(ctx, "File Browser", nk_rect(50, 50, 800, 600),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
+ {
+ 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)) {
+ *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, "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))
+ file_browser_reload_directory_content(browser, browser->home);
+ if (nk_button_image_label(ctx,desktop,"desktop",NK_TEXT_CENTERED))
+ file_browser_reload_directory_content(browser, browser->desktop);
+ if (nk_button_image_label(ctx,computer,"computer",NK_TEXT_CENTERED))
+ file_browser_reload_directory_content(browser, "/");
+ nk_group_end(ctx);
+ }
+
+ /* output directory content window */
+ nk_group_begin(ctx, "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))
+ 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)) {
+ 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);
+ }
+ nk_group_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ return ret;
+}
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+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 =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_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,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ 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;
+
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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 * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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;
+ int display_width = 0, display_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, 13.0f, NULL);
+ else font = nk_font_atlas_add_default(&atlas, 13.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))
+ {
+ /* High DPI displays */
+ struct nk_vec2 scale;
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* 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) == GLFW_PRESS) {
+ 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 */
+ glViewport(0, 0, display_width, display_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ device_draw(&device, &ctx, width, height, scale, 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;
+}
+
+
diff --git a/nuklear/example/icon/checked.png b/nuklear/example/icon/checked.png
new file mode 100644
index 0000000..e4e05b2
--- /dev/null
+++ b/nuklear/example/icon/checked.png
Binary files differ
diff --git a/nuklear/example/icon/cloud.png b/nuklear/example/icon/cloud.png
new file mode 100644
index 0000000..ecc5791
--- /dev/null
+++ b/nuklear/example/icon/cloud.png
Binary files differ
diff --git a/nuklear/example/icon/computer.png b/nuklear/example/icon/computer.png
new file mode 100644
index 0000000..29db8fc
--- /dev/null
+++ b/nuklear/example/icon/computer.png
Binary files differ
diff --git a/nuklear/example/icon/copy.png b/nuklear/example/icon/copy.png
new file mode 100644
index 0000000..0a6e979
--- /dev/null
+++ b/nuklear/example/icon/copy.png
Binary files differ
diff --git a/nuklear/example/icon/default.png b/nuklear/example/icon/default.png
new file mode 100644
index 0000000..c11145a
--- /dev/null
+++ b/nuklear/example/icon/default.png
Binary files differ
diff --git a/nuklear/example/icon/delete.png b/nuklear/example/icon/delete.png
new file mode 100644
index 0000000..7bc6dde
--- /dev/null
+++ b/nuklear/example/icon/delete.png
Binary files differ
diff --git a/nuklear/example/icon/desktop.png b/nuklear/example/icon/desktop.png
new file mode 100644
index 0000000..b4abcfd
--- /dev/null
+++ b/nuklear/example/icon/desktop.png
Binary files differ
diff --git a/nuklear/example/icon/directory.png b/nuklear/example/icon/directory.png
new file mode 100644
index 0000000..4c73d37
--- /dev/null
+++ b/nuklear/example/icon/directory.png
Binary files differ
diff --git a/nuklear/example/icon/edit.png b/nuklear/example/icon/edit.png
new file mode 100644
index 0000000..62ce0b4
--- /dev/null
+++ b/nuklear/example/icon/edit.png
Binary files differ
diff --git a/nuklear/example/icon/export.png b/nuklear/example/icon/export.png
new file mode 100644
index 0000000..ff6b5aa
--- /dev/null
+++ b/nuklear/example/icon/export.png
Binary files differ
diff --git a/nuklear/example/icon/font.png b/nuklear/example/icon/font.png
new file mode 100644
index 0000000..918e9bf
--- /dev/null
+++ b/nuklear/example/icon/font.png
Binary files differ
diff --git a/nuklear/example/icon/home.png b/nuklear/example/icon/home.png
new file mode 100644
index 0000000..8560626
--- /dev/null
+++ b/nuklear/example/icon/home.png
Binary files differ
diff --git a/nuklear/example/icon/img.png b/nuklear/example/icon/img.png
new file mode 100644
index 0000000..1985957
--- /dev/null
+++ b/nuklear/example/icon/img.png
Binary files differ
diff --git a/nuklear/example/icon/movie.png b/nuklear/example/icon/movie.png
new file mode 100644
index 0000000..5227883
--- /dev/null
+++ b/nuklear/example/icon/movie.png
Binary files differ
diff --git a/nuklear/example/icon/music.png b/nuklear/example/icon/music.png
new file mode 100644
index 0000000..0f1415c
--- /dev/null
+++ b/nuklear/example/icon/music.png
Binary files differ
diff --git a/nuklear/example/icon/next.png b/nuklear/example/icon/next.png
new file mode 100644
index 0000000..af0b98d
--- /dev/null
+++ b/nuklear/example/icon/next.png
Binary files differ
diff --git a/nuklear/example/icon/pause.png b/nuklear/example/icon/pause.png
new file mode 100644
index 0000000..7d6367e
--- /dev/null
+++ b/nuklear/example/icon/pause.png
Binary files differ
diff --git a/nuklear/example/icon/pen.png b/nuklear/example/icon/pen.png
new file mode 100644
index 0000000..10c851c
--- /dev/null
+++ b/nuklear/example/icon/pen.png
Binary files differ
diff --git a/nuklear/example/icon/phone.png b/nuklear/example/icon/phone.png
new file mode 100644
index 0000000..5e6f613
--- /dev/null
+++ b/nuklear/example/icon/phone.png
Binary files differ
diff --git a/nuklear/example/icon/plane.png b/nuklear/example/icon/plane.png
new file mode 100644
index 0000000..3a98489
--- /dev/null
+++ b/nuklear/example/icon/plane.png
Binary files differ
diff --git a/nuklear/example/icon/play.png b/nuklear/example/icon/play.png
new file mode 100644
index 0000000..9c9e8f0
--- /dev/null
+++ b/nuklear/example/icon/play.png
Binary files differ
diff --git a/nuklear/example/icon/prev.png b/nuklear/example/icon/prev.png
new file mode 100644
index 0000000..0eecc2e
--- /dev/null
+++ b/nuklear/example/icon/prev.png
Binary files differ
diff --git a/nuklear/example/icon/rocket.png b/nuklear/example/icon/rocket.png
new file mode 100644
index 0000000..ea8e187
--- /dev/null
+++ b/nuklear/example/icon/rocket.png
Binary files differ
diff --git a/nuklear/example/icon/settings.png b/nuklear/example/icon/settings.png
new file mode 100644
index 0000000..e6e13f8
--- /dev/null
+++ b/nuklear/example/icon/settings.png
Binary files differ
diff --git a/nuklear/example/icon/stop.png b/nuklear/example/icon/stop.png
new file mode 100644
index 0000000..6742baf
--- /dev/null
+++ b/nuklear/example/icon/stop.png
Binary files differ
diff --git a/nuklear/example/icon/text.png b/nuklear/example/icon/text.png
new file mode 100644
index 0000000..136e534
--- /dev/null
+++ b/nuklear/example/icon/text.png
Binary files differ
diff --git a/nuklear/example/icon/tools.png b/nuklear/example/icon/tools.png
new file mode 100644
index 0000000..412ff85
--- /dev/null
+++ b/nuklear/example/icon/tools.png
Binary files differ
diff --git a/nuklear/example/icon/unchecked.png b/nuklear/example/icon/unchecked.png
new file mode 100644
index 0000000..fca94d2
--- /dev/null
+++ b/nuklear/example/icon/unchecked.png
Binary files differ
diff --git a/nuklear/example/icon/volume.png b/nuklear/example/icon/volume.png
new file mode 100644
index 0000000..8e86fa9
--- /dev/null
+++ b/nuklear/example/icon/volume.png
Binary files differ
diff --git a/nuklear/example/icon/wifi.png b/nuklear/example/icon/wifi.png
new file mode 100644
index 0000000..270d55d
--- /dev/null
+++ b/nuklear/example/icon/wifi.png
Binary files differ
diff --git a/nuklear/example/images/image1.png b/nuklear/example/images/image1.png
new file mode 100644
index 0000000..66a2b63
--- /dev/null
+++ b/nuklear/example/images/image1.png
Binary files differ
diff --git a/nuklear/example/images/image2.png b/nuklear/example/images/image2.png
new file mode 100644
index 0000000..4acafe5
--- /dev/null
+++ b/nuklear/example/images/image2.png
Binary files differ
diff --git a/nuklear/example/images/image3.png b/nuklear/example/images/image3.png
new file mode 100644
index 0000000..4dfe664
--- /dev/null
+++ b/nuklear/example/images/image3.png
Binary files differ
diff --git a/nuklear/example/images/image4.png b/nuklear/example/images/image4.png
new file mode 100644
index 0000000..d2f16d0
--- /dev/null
+++ b/nuklear/example/images/image4.png
Binary files differ
diff --git a/nuklear/example/images/image5.png b/nuklear/example/images/image5.png
new file mode 100644
index 0000000..852fd70
--- /dev/null
+++ b/nuklear/example/images/image5.png
Binary files differ
diff --git a/nuklear/example/images/image6.png b/nuklear/example/images/image6.png
new file mode 100644
index 0000000..0e261cb
--- /dev/null
+++ b/nuklear/example/images/image6.png
Binary files differ
diff --git a/nuklear/example/images/image7.png b/nuklear/example/images/image7.png
new file mode 100644
index 0000000..f61325b
--- /dev/null
+++ b/nuklear/example/images/image7.png
Binary files differ
diff --git a/nuklear/example/images/image8.png b/nuklear/example/images/image8.png
new file mode 100644
index 0000000..6b27cb8
--- /dev/null
+++ b/nuklear/example/images/image8.png
Binary files differ
diff --git a/nuklear/example/images/image9.png b/nuklear/example/images/image9.png
new file mode 100644
index 0000000..516929e
--- /dev/null
+++ b/nuklear/example/images/image9.png
Binary files differ
diff --git a/nuklear/example/skinning.c b/nuklear/example/skinning.c
new file mode 100644
index 0000000..4634b09
--- /dev/null
+++ b/nuklear/example/skinning.c
@@ -0,0 +1,825 @@
+/* nuklear - v1.05 - 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 <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])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+struct media {
+ GLint skin;
+ struct nk_image menu;
+ struct nk_image check;
+ struct nk_image check_cursor;
+ struct nk_image option;
+ struct nk_image option_cursor;
+ struct nk_image header;
+ struct nk_image window;
+ struct nk_image scrollbar_inc_button;
+ struct nk_image scrollbar_inc_button_hover;
+ struct nk_image scrollbar_dec_button;
+ struct nk_image scrollbar_dec_button_hover;
+ struct nk_image button;
+ struct nk_image button_hover;
+ struct nk_image button_active;
+ struct nk_image tab_minimize;
+ struct nk_image tab_maximize;
+ struct nk_image slider;
+ struct nk_image slider_hover;
+ struct nk_image slider_active;
+};
+
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+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 GLuint
+image_load(const char *filename)
+{
+ int x,y,n;
+ GLuint tex;
+ unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+ if (!data) die("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 tex;
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "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 =
+ NK_SHADER_VERSION
+ "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_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_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,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ 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;
+
+ /* 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 convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {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 * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ 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;
+ int display_width=0, display_height=0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct media media;
+ struct nk_context ctx;
+ struct nk_font *font;
+
+ /* 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);
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+
+ /* 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, 13.0f, NULL);
+ else font = nk_font_atlas_add_default(&atlas, 13.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);}
+
+ { /* skin */
+ glEnable(GL_TEXTURE_2D);
+ media.skin = image_load("../skins/gwen.png");
+ media.check = nk_subimage_id(media.skin, 512,512, nk_rect(464,32,15,15));
+ media.check_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(450,34,11,11));
+ media.option = nk_subimage_id(media.skin, 512,512, nk_rect(464,64,15,15));
+ media.option_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(451,67,9,9));
+ media.header = nk_subimage_id(media.skin, 512,512, nk_rect(128,0,127,24));
+ media.window = nk_subimage_id(media.skin, 512,512, nk_rect(128,23,127,104));
+ media.scrollbar_inc_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,256,15,15));
+ media.scrollbar_inc_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,320,15,15));
+ media.scrollbar_dec_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,224,15,15));
+ media.scrollbar_dec_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,288,15,15));
+ media.button = nk_subimage_id(media.skin, 512,512, nk_rect(384,336,127,31));
+ media.button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(384,368,127,31));
+ media.button_active = nk_subimage_id(media.skin, 512,512, nk_rect(384,400,127,31));
+ media.tab_minimize = nk_subimage_id(media.skin, 512,512, nk_rect(451, 99, 9, 9));
+ media.tab_maximize = nk_subimage_id(media.skin, 512,512, nk_rect(467,99,9,9));
+ media.slider = nk_subimage_id(media.skin, 512,512, nk_rect(418,33,11,14));
+ media.slider_hover = nk_subimage_id(media.skin, 512,512, nk_rect(418,49,11,14));
+ media.slider_active = nk_subimage_id(media.skin, 512,512, nk_rect(418,64,11,14));
+
+ /* window */
+ ctx.style.window.background = nk_rgb(204,204,204);
+ ctx.style.window.fixed_background = nk_style_item_image(media.window);
+ ctx.style.window.border_color = nk_rgb(67,67,67);
+ ctx.style.window.combo_border_color = nk_rgb(67,67,67);
+ ctx.style.window.contextual_border_color = nk_rgb(67,67,67);
+ ctx.style.window.menu_border_color = nk_rgb(67,67,67);
+ ctx.style.window.group_border_color = nk_rgb(67,67,67);
+ ctx.style.window.tooltip_border_color = nk_rgb(67,67,67);
+ ctx.style.window.scrollbar_size = nk_vec2(16,16);
+ ctx.style.window.border_color = nk_rgba(0,0,0,0);
+ ctx.style.window.padding = nk_vec2(8,4);
+ ctx.style.window.border = 3;
+
+ /* window header */
+ ctx.style.window.header;
+ ctx.style.window.header.normal = nk_style_item_image(media.header);
+ ctx.style.window.header.hover = nk_style_item_image(media.header);
+ ctx.style.window.header.active = nk_style_item_image(media.header);
+ ctx.style.window.header.label_normal = nk_rgb(95,95,95);
+ ctx.style.window.header.label_hover = nk_rgb(95,95,95);
+ ctx.style.window.header.label_active = nk_rgb(95,95,95);
+
+ /* scrollbar */
+ ctx.style.scrollv.normal = nk_style_item_color(nk_rgb(184,184,184));
+ ctx.style.scrollv.hover = nk_style_item_color(nk_rgb(184,184,184));
+ ctx.style.scrollv.active = nk_style_item_color(nk_rgb(184,184,184));
+ ctx.style.scrollv.cursor_normal = nk_style_item_color(nk_rgb(220,220,220));
+ ctx.style.scrollv.cursor_hover = nk_style_item_color(nk_rgb(235,235,235));
+ ctx.style.scrollv.cursor_active = nk_style_item_color(nk_rgb(99,202,255));
+ ctx.style.scrollv.dec_symbol = NK_SYMBOL_NONE;
+ ctx.style.scrollv.inc_symbol = NK_SYMBOL_NONE;
+ ctx.style.scrollv.show_buttons = nk_true;
+ ctx.style.scrollv.border_color = nk_rgb(81,81,81);
+ ctx.style.scrollv.cursor_border_color = nk_rgb(81,81,81);
+ ctx.style.scrollv.border = 1;
+ ctx.style.scrollv.rounding = 0;
+ ctx.style.scrollv.border_cursor = 1;
+ ctx.style.scrollv.rounding_cursor = 2;
+
+ /* scrollbar buttons */
+ ctx.style.scrollv.inc_button.normal = nk_style_item_image(media.scrollbar_inc_button);
+ ctx.style.scrollv.inc_button.hover = nk_style_item_image(media.scrollbar_inc_button_hover);
+ ctx.style.scrollv.inc_button.active = nk_style_item_image(media.scrollbar_inc_button_hover);
+ ctx.style.scrollv.inc_button.border_color = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.inc_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.inc_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.inc_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.inc_button.text_active = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.inc_button.border = 0.0f;
+
+ ctx.style.scrollv.dec_button.normal = nk_style_item_image(media.scrollbar_dec_button);
+ ctx.style.scrollv.dec_button.hover = nk_style_item_image(media.scrollbar_dec_button_hover);
+ ctx.style.scrollv.dec_button.active = nk_style_item_image(media.scrollbar_dec_button_hover);
+ ctx.style.scrollv.dec_button.border_color = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.dec_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.dec_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.dec_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.dec_button.text_active = nk_rgba(0,0,0,0);
+ ctx.style.scrollv.dec_button.border = 0.0f;
+
+ /* checkbox toggle */
+ {struct nk_style_toggle *toggle;
+ toggle = &ctx.style.checkbox;
+ toggle->normal = nk_style_item_image(media.check);
+ toggle->hover = nk_style_item_image(media.check);
+ toggle->active = nk_style_item_image(media.check);
+ toggle->cursor_normal = nk_style_item_image(media.check_cursor);
+ toggle->cursor_hover = nk_style_item_image(media.check_cursor);
+ toggle->text_normal = nk_rgb(95,95,95);
+ toggle->text_hover = nk_rgb(95,95,95);
+ toggle->text_active = nk_rgb(95,95,95);}
+
+ /* option toggle */
+ {struct nk_style_toggle *toggle;
+ toggle = &ctx.style.option;
+ toggle->normal = nk_style_item_image(media.option);
+ toggle->hover = nk_style_item_image(media.option);
+ toggle->active = nk_style_item_image(media.option);
+ toggle->cursor_normal = nk_style_item_image(media.option_cursor);
+ toggle->cursor_hover = nk_style_item_image(media.option_cursor);
+ toggle->text_normal = nk_rgb(95,95,95);
+ toggle->text_hover = nk_rgb(95,95,95);
+ toggle->text_active = nk_rgb(95,95,95);}
+
+ /* default button */
+ ctx.style.button.normal = nk_style_item_image(media.button);
+ ctx.style.button.hover = nk_style_item_image(media.button_hover);
+ ctx.style.button.active = nk_style_item_image(media.button_active);
+ ctx.style.button.border_color = nk_rgba(0,0,0,0);
+ ctx.style.button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.button.text_normal = nk_rgb(95,95,95);
+ ctx.style.button.text_hover = nk_rgb(95,95,95);
+ ctx.style.button.text_active = nk_rgb(95,95,95);
+
+ /* default text */
+ ctx.style.text.color = nk_rgb(95,95,95);
+
+ /* contextual button */
+ ctx.style.contextual_button.normal = nk_style_item_color(nk_rgb(206,206,206));
+ ctx.style.contextual_button.hover = nk_style_item_color(nk_rgb(229,229,229));
+ ctx.style.contextual_button.active = nk_style_item_color(nk_rgb(99,202,255));
+ ctx.style.contextual_button.border_color = nk_rgba(0,0,0,0);
+ ctx.style.contextual_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.contextual_button.text_normal = nk_rgb(95,95,95);
+ ctx.style.contextual_button.text_hover = nk_rgb(95,95,95);
+ ctx.style.contextual_button.text_active = nk_rgb(95,95,95);
+
+ /* menu button */
+ ctx.style.menu_button.normal = nk_style_item_color(nk_rgb(206,206,206));
+ ctx.style.menu_button.hover = nk_style_item_color(nk_rgb(229,229,229));
+ ctx.style.menu_button.active = nk_style_item_color(nk_rgb(99,202,255));
+ ctx.style.menu_button.border_color = nk_rgba(0,0,0,0);
+ ctx.style.menu_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.menu_button.text_normal = nk_rgb(95,95,95);
+ ctx.style.menu_button.text_hover = nk_rgb(95,95,95);
+ ctx.style.menu_button.text_active = nk_rgb(95,95,95);
+
+ /* tree */
+ ctx.style.tab.text = nk_rgb(95,95,95);
+ ctx.style.tab.tab_minimize_button.normal = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.tab_minimize_button.hover = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.tab_minimize_button.active = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.tab_minimize_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_minimize_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_minimize_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_minimize_button.text_active = nk_rgba(0,0,0,0);
+
+ ctx.style.tab.tab_maximize_button.normal = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.tab_maximize_button.hover = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.tab_maximize_button.active = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.tab_maximize_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_maximize_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_maximize_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.tab.tab_maximize_button.text_active = nk_rgba(0,0,0,0);
+
+ ctx.style.tab.node_minimize_button.normal = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.node_minimize_button.hover = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.node_minimize_button.active = nk_style_item_image(media.tab_minimize);
+ ctx.style.tab.node_minimize_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_minimize_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_minimize_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_minimize_button.text_active = nk_rgba(0,0,0,0);
+
+ ctx.style.tab.node_maximize_button.normal = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.node_maximize_button.hover = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.node_maximize_button.active = nk_style_item_image(media.tab_maximize);
+ ctx.style.tab.node_maximize_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_maximize_button.text_normal = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_maximize_button.text_hover = nk_rgba(0,0,0,0);
+ ctx.style.tab.node_maximize_button.text_active = nk_rgba(0,0,0,0);
+
+ /* selectable */
+ ctx.style.selectable.normal = nk_style_item_color(nk_rgb(206,206,206));
+ ctx.style.selectable.hover = nk_style_item_color(nk_rgb(206,206,206));
+ ctx.style.selectable.pressed = nk_style_item_color(nk_rgb(206,206,206));
+ ctx.style.selectable.normal_active = nk_style_item_color(nk_rgb(185,205,248));
+ ctx.style.selectable.hover_active = nk_style_item_color(nk_rgb(185,205,248));
+ ctx.style.selectable.pressed_active = nk_style_item_color(nk_rgb(185,205,248));
+ ctx.style.selectable.text_normal = nk_rgb(95,95,95);
+ ctx.style.selectable.text_hover = nk_rgb(95,95,95);
+ ctx.style.selectable.text_pressed = nk_rgb(95,95,95);
+ ctx.style.selectable.text_normal_active = nk_rgb(95,95,95);
+ ctx.style.selectable.text_hover_active = nk_rgb(95,95,95);
+ ctx.style.selectable.text_pressed_active = nk_rgb(95,95,95);
+
+ /* slider */
+ ctx.style.slider.normal = nk_style_item_hide();
+ ctx.style.slider.hover = nk_style_item_hide();
+ ctx.style.slider.active = nk_style_item_hide();
+ ctx.style.slider.bar_normal = nk_rgb(156,156,156);
+ ctx.style.slider.bar_hover = nk_rgb(156,156,156);
+ ctx.style.slider.bar_active = nk_rgb(156,156,156);
+ ctx.style.slider.bar_filled = nk_rgb(156,156,156);
+ ctx.style.slider.cursor_normal = nk_style_item_image(media.slider);
+ ctx.style.slider.cursor_hover = nk_style_item_image(media.slider_hover);
+ ctx.style.slider.cursor_active = nk_style_item_image(media.slider_active);
+ ctx.style.slider.cursor_size = nk_vec2(16.5f,21);
+ ctx.style.slider.bar_height = 1;
+
+ /* progressbar */
+ ctx.style.progress.normal = nk_style_item_color(nk_rgb(231,231,231));
+ ctx.style.progress.hover = nk_style_item_color(nk_rgb(231,231,231));
+ ctx.style.progress.active = nk_style_item_color(nk_rgb(231,231,231));
+ ctx.style.progress.cursor_normal = nk_style_item_color(nk_rgb(63,242,93));
+ ctx.style.progress.cursor_hover = nk_style_item_color(nk_rgb(63,242,93));
+ ctx.style.progress.cursor_active = nk_style_item_color(nk_rgb(63,242,93));
+ ctx.style.progress.border_color = nk_rgb(114,116,115);
+ ctx.style.progress.padding = nk_vec2(0,0);
+ ctx.style.progress.border = 2;
+ ctx.style.progress.rounding = 1;
+
+ /* combo */
+ ctx.style.combo.normal = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.hover = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.active = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.border_color = nk_rgb(95,95,95);
+ ctx.style.combo.label_normal = nk_rgb(95,95,95);
+ ctx.style.combo.label_hover = nk_rgb(95,95,95);
+ ctx.style.combo.label_active = nk_rgb(95,95,95);
+ ctx.style.combo.border = 1;
+ ctx.style.combo.rounding = 1;
+
+ /* combo button */
+ ctx.style.combo.button.normal = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.button.hover = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.button.active = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.combo.button.text_background = nk_rgb(216,216,216);
+ ctx.style.combo.button.text_normal = nk_rgb(95,95,95);
+ ctx.style.combo.button.text_hover = nk_rgb(95,95,95);
+ ctx.style.combo.button.text_active = nk_rgb(95,95,95);
+
+ /* property */
+ ctx.style.property.normal = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.hover = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.active = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.border_color = nk_rgb(81,81,81);
+ ctx.style.property.label_normal = nk_rgb(95,95,95);
+ ctx.style.property.label_hover = nk_rgb(95,95,95);
+ ctx.style.property.label_active = nk_rgb(95,95,95);
+ ctx.style.property.sym_left = NK_SYMBOL_TRIANGLE_LEFT;
+ ctx.style.property.sym_right = NK_SYMBOL_TRIANGLE_RIGHT;
+ ctx.style.property.rounding = 10;
+ ctx.style.property.border = 1;
+
+ /* edit */
+ ctx.style.edit.normal = nk_style_item_color(nk_rgb(240,240,240));
+ ctx.style.edit.hover = nk_style_item_color(nk_rgb(240,240,240));
+ ctx.style.edit.active = nk_style_item_color(nk_rgb(240,240,240));
+ ctx.style.edit.border_color = nk_rgb(62,62,62);
+ ctx.style.edit.cursor_normal = nk_rgb(99,202,255);
+ ctx.style.edit.cursor_hover = nk_rgb(99,202,255);
+ ctx.style.edit.cursor_text_normal = nk_rgb(95,95,95);
+ ctx.style.edit.cursor_text_hover = nk_rgb(95,95,95);
+ ctx.style.edit.text_normal = nk_rgb(95,95,95);
+ ctx.style.edit.text_hover = nk_rgb(95,95,95);
+ ctx.style.edit.text_active = nk_rgb(95,95,95);
+ ctx.style.edit.selected_normal = nk_rgb(99,202,255);
+ ctx.style.edit.selected_hover = nk_rgb(99,202,255);
+ ctx.style.edit.selected_text_normal = nk_rgb(95,95,95);
+ ctx.style.edit.selected_text_hover = nk_rgb(95,95,95);
+ ctx.style.edit.border = 1;
+ ctx.style.edit.rounding = 2;
+
+ /* property buttons */
+ ctx.style.property.dec_button.normal = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.dec_button.hover = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.dec_button.active = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.dec_button.text_background = nk_rgba(0,0,0,0);
+ ctx.style.property.dec_button.text_normal = nk_rgb(95,95,95);
+ ctx.style.property.dec_button.text_hover = nk_rgb(95,95,95);
+ ctx.style.property.dec_button.text_active = nk_rgb(95,95,95);
+ ctx.style.property.inc_button = ctx.style.property.dec_button;
+
+ /* property edit */
+ ctx.style.property.edit.normal = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.edit.hover = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.edit.active = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.property.edit.border_color = nk_rgba(0,0,0,0);
+ ctx.style.property.edit.cursor_normal = nk_rgb(95,95,95);
+ ctx.style.property.edit.cursor_hover = nk_rgb(95,95,95);
+ ctx.style.property.edit.cursor_text_normal = nk_rgb(216,216,216);
+ ctx.style.property.edit.cursor_text_hover = nk_rgb(216,216,216);
+ ctx.style.property.edit.text_normal = nk_rgb(95,95,95);
+ ctx.style.property.edit.text_hover = nk_rgb(95,95,95);
+ ctx.style.property.edit.text_active = nk_rgb(95,95,95);
+ ctx.style.property.edit.selected_normal = nk_rgb(95,95,95);
+ ctx.style.property.edit.selected_hover = nk_rgb(95,95,95);
+ ctx.style.property.edit.selected_text_normal = nk_rgb(216,216,216);
+ ctx.style.property.edit.selected_text_hover = nk_rgb(216,216,216);
+
+ /* chart */
+ ctx.style.chart.background = nk_style_item_color(nk_rgb(216,216,216));
+ ctx.style.chart.border_color = nk_rgb(81,81,81);
+ ctx.style.chart.color = nk_rgb(95,95,95);
+ ctx.style.chart.selected_color = nk_rgb(255,0,0);
+ ctx.style.chart.border = 1;
+ }
+
+ while (!glfwWindowShouldClose(win))
+ {
+ /* High DPI displays */
+ struct nk_vec2 scale;
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* 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) == GLFW_PRESS) {
+ 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 */
+ {struct nk_panel layout, tab;
+ if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 300, 400),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE))
+ {
+ int i;
+ float id;
+ static int slider = 10;
+ static int field_len;
+ static nk_size prog_value = 60;
+ static int current_weapon = 0;
+ static char field_buffer[64];
+ static float pos;
+ static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"};
+ const float step = (2*3.141592654f) / 32;
+
+ nk_layout_row_static(&ctx, 30, 120, 1);
+ if (nk_button_label(&ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ nk_label(&ctx, "Label", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(&ctx, 30, 2);
+ nk_check_label(&ctx, "inactive", 0);
+ nk_check_label(&ctx, "active", 1);
+ nk_option_label(&ctx, "active", 1);
+ nk_option_label(&ctx, "inactive", 0);
+
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ nk_slider_int(&ctx, 0, &slider, 16, 1);
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ nk_progress(&ctx, &prog_value, 100, NK_MODIFIABLE);
+
+ nk_layout_row_dynamic(&ctx, 25, 1);
+ nk_edit_string(&ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);
+ nk_property_float(&ctx, "#X:", -1024.0f, &pos, 1024.0f, 1, 1);
+ current_weapon = nk_combo(&ctx, weapons, LEN(weapons), current_weapon, 25, nk_vec2(nk_widget_width(&ctx),200));
+
+ nk_layout_row_dynamic(&ctx, 100, 1);
+ if (nk_chart_begin_colored(&ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f);
+ for (id = 0, i = 0; i < 32; ++i) {
+ nk_chart_push_slot(&ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(&ctx, (float)cos(id), 1);
+ nk_chart_push_slot(&ctx, (float)sin(id), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(&ctx);
+
+ nk_layout_row_dynamic(&ctx, 250, 1);
+ if (nk_group_begin(&ctx, "Standard", NK_WINDOW_BORDER|NK_WINDOW_BORDER))
+ {
+ if (nk_tree_push(&ctx, NK_TREE_NODE, "Window", NK_MAXIMIZED)) {
+ static int selected[8];
+ if (nk_tree_push(&ctx, NK_TREE_NODE, "Next", NK_MAXIMIZED)) {
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ for (i = 0; i < 4; ++i)
+ nk_selectable_label(&ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_LEFT, &selected[i]);
+ nk_tree_pop(&ctx);
+ }
+ if (nk_tree_push(&ctx, NK_TREE_NODE, "Previous", NK_MAXIMIZED)) {
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ for (i = 4; i < 8; ++i)
+ nk_selectable_label(&ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_LEFT, &selected[i]);
+ nk_tree_pop(&ctx);
+ }
+ nk_tree_pop(&ctx);
+ }
+ nk_group_end(&ctx);
+ }
+ }
+ nk_end(&ctx);}
+
+ /* Draw */
+ glViewport(0, 0, display_width, display_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.5882, 0.6666, 0.6666, 1.0f);
+ device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+ glfwSwapBuffers(win);
+ }
+ glDeleteTextures(1,(const GLuint*)&media.skin);
+ nk_font_atlas_clear(&atlas);
+ nk_free(&ctx);
+ device_shutdown(&device);
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/example/skins/gwen.png b/nuklear/example/skins/gwen.png
new file mode 100644
index 0000000..40956c9
--- /dev/null
+++ b/nuklear/example/skins/gwen.png
Binary files differ
diff --git a/nuklear/example/stb_image.h b/nuklear/example/stb_image.h
new file mode 100644
index 0000000..0a9de39
--- /dev/null
+++ b/nuklear/example/stb_image.h
@@ -0,0 +1,6509 @@
+/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h
+ no warranty implied; use at your own risk
+
+ Do this:
+ #define STB_IMAGE_IMPLEMENTATION
+ before you include this file in *one* C or C++ file to create the implementation.
+
+ // i.e. it should look like this:
+ #include ...
+ #include ...
+ #include ...
+ #define STB_IMAGE_IMPLEMENTATION
+ #include "stb_image.h"
+
+ You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+ And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+ QUICK NOTES:
+ Primarily of interest to game developers and other people who can
+ avoid problematic images and only need the trivial interface
+
+ JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+ PNG 1/2/4/8-bit-per-channel (16 bpc not supported)
+
+ TGA (not sure what subset, if a subset)
+ BMP non-1bpp, non-RLE
+ PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+ GIF (*comp always reports as 4-channel)
+ HDR (radiance rgbE format)
+ PIC (Softimage PIC)
+ PNM (PPM and PGM binary only)
+
+ Animated GIF still needs a proper API, but here's one way to do it:
+ http://gist.github.com/urraka/685d9a6340b26b830d49
+
+ - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+ - decode from arbitrary I/O callbacks
+ - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+ Full documentation under "DOCUMENTATION" below.
+
+
+ Revision 2.00 release notes:
+
+ - Progressive JPEG is now supported.
+
+ - PPM and PGM binary formats are now supported, thanks to Ken Miller.
+
+ - x86 platforms now make use of SSE2 SIMD instructions for
+ JPEG decoding, and ARM platforms can use NEON SIMD if requested.
+ This work was done by Fabian "ryg" Giesen. SSE2 is used by
+ default, but NEON must be enabled explicitly; see docs.
+
+ With other JPEG optimizations included in this version, we see
+ 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup
+ on a JPEG on an ARM machine, relative to previous versions of this
+ library. The same results will not obtain for all JPGs and for all
+ x86/ARM machines. (Note that progressive JPEGs are significantly
+ slower to decode than regular JPEGs.) This doesn't mean that this
+ is the fastest JPEG decoder in the land; rather, it brings it
+ closer to parity with standard libraries. If you want the fastest
+ decode, look elsewhere. (See "Philosophy" section of docs below.)
+
+ See final bullet items below for more info on SIMD.
+
+ - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing
+ the memory allocator. Unlike other STBI libraries, these macros don't
+ support a context parameter, so if you need to pass a context in to
+ the allocator, you'll have to store it in a global or a thread-local
+ variable.
+
+ - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and
+ STBI_NO_LINEAR.
+ STBI_NO_HDR: suppress implementation of .hdr reader format
+ STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API
+
+ - You can suppress implementation of any of the decoders to reduce
+ your code footprint by #defining one or more of the following
+ symbols before creating the implementation.
+
+ STBI_NO_JPEG
+ STBI_NO_PNG
+ STBI_NO_BMP
+ STBI_NO_PSD
+ STBI_NO_TGA
+ STBI_NO_GIF
+ STBI_NO_HDR
+ STBI_NO_PIC
+ STBI_NO_PNM (.ppm and .pgm)
+
+ - You can request *only* certain decoders and suppress all other ones
+ (this will be more forward-compatible, as addition of new decoders
+ doesn't require you to disable them explicitly):
+
+ STBI_ONLY_JPEG
+ STBI_ONLY_PNG
+ STBI_ONLY_BMP
+ STBI_ONLY_PSD
+ STBI_ONLY_TGA
+ STBI_ONLY_GIF
+ STBI_ONLY_HDR
+ STBI_ONLY_PIC
+ STBI_ONLY_PNM (.ppm and .pgm)
+
+ Note that you can define multiples of these, and you will get all
+ of them ("only x" and "only y" is interpreted to mean "only x&y").
+
+ - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+ want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+
+ - Compilation of all SIMD code can be suppressed with
+ #define STBI_NO_SIMD
+ It should not be necessary to disable SIMD unless you have issues
+ compiling (e.g. using an x86 compiler which doesn't support SSE
+ intrinsics or that doesn't support the method used to detect
+ SSE2 support at run-time), and even those can be reported as
+ bugs so I can refine the built-in compile-time checking to be
+ smarter.
+
+ - The old STBI_SIMD system which allowed installing a user-defined
+ IDCT etc. has been removed. If you need this, don't upgrade. My
+ assumption is that almost nobody was doing this, and those who
+ were will find the built-in SIMD more satisfactory anyway.
+
+ - RGB values computed for JPEG images are slightly different from
+ previous versions of stb_image. (This is due to using less
+ integer precision in SIMD.) The C code has been adjusted so
+ that the same RGB values will be computed regardless of whether
+ SIMD support is available, so your app should always produce
+ consistent results. But these results are slightly different from
+ previous versions. (Specifically, about 3% of available YCbCr values
+ will compute different RGB results from pre-1.49 versions by +-1;
+ most of the deviating values are one smaller in the G channel.)
+
+ - If you must produce consistent results with previous versions of
+ stb_image, #define STBI_JPEG_OLD and you will get the same results
+ you used to; however, you will not get the SIMD speedups for
+ the YCbCr-to-RGB conversion step (although you should still see
+ significant JPEG speedup from the other changes).
+
+ Please note that STBI_JPEG_OLD is a temporary feature; it will be
+ removed in future versions of the library. It is only intended for
+ near-term back-compatibility use.
+
+
+ Latest revision history:
+ 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+ 2.07 (2015-09-13) partial animated GIF support
+ limited 16-bit PSD support
+ minor bugs, code cleanup, and compiler warnings
+ 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
+ 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
+ 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+ 2.03 (2015-04-12) additional corruption checking
+ stbi_set_flip_vertically_on_load
+ fix NEON support; fix mingw support
+ 2.02 (2015-01-19) fix incorrect assert, fix warning
+ 2.01 (2015-01-17) fix various warnings
+ 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+ 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
+ progressive JPEG
+ PGM/PPM support
+ STBI_MALLOC,STBI_REALLOC,STBI_FREE
+ STBI_NO_*, STBI_ONLY_*
+ GIF bugfix
+ 1.48 (2014-12-14) fix incorrectly-named assert()
+ 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)
+ optimize PNG
+ fix bug in interlaced PNG with user-specified channel count
+
+ See end of file for full revision history.
+
+
+ ============================ Contributors =========================
+
+ Image formats Bug fixes & warning fixes
+ Sean Barrett (jpeg, png, bmp) Marc LeBlanc
+ Nicolas Schulz (hdr, psd) Christpher Lloyd
+ Jonathan Dummer (tga) Dave Moore
+ Jean-Marc Lienher (gif) Won Chun
+ Tom Seddon (pic) the Horde3D community
+ Thatcher Ulrich (psd) Janez Zemva
+ Ken Miller (pgm, ppm) Jonathan Blow
+ urraka@github (animated gif) Laurent Gomila
+ Aruelien Pocheville
+ Ryamond Barbiero
+ David Woo
+ Extensions, features Martin Golini
+ Jetro Lauha (stbi_info) Roy Eltham
+ Martin "SpartanJ" Golini (stbi_info) Luke Graham
+ James "moose2000" Brown (iPhone PNG) Thomas Ruf
+ Ben "Disch" Wenger (io callbacks) John Bartholomew
+ Omar Cornut (1/2/4-bit PNG) Ken Hamada
+ Nicolas Guillemot (vertical flip) Cort Stratton
+ Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski
+ Thibault Reuille
+ Paul Du Bois
+ Guillaume George
+ Jerry Jansson
+ Hayaki Saito
+ Johan Duparc
+ Ronny Chevalier
+ Optimizations & bugfixes Michal Cichon
+ Fabian "ryg" Giesen Tero Hanninen
+ Arseny Kapoulkine Sergio Gonzalez
+ Cass Everitt
+ Engin Manap
+ If your name should be here but Martins Mozeiko
+ isn't, let Sean know. Joseph Thomson
+ Phil Jordan
+ Nathan Reed
+ Michaelangel007@github
+ Nick Verigakis
+
+LICENSE
+
+This software is in the public domain. Where that dedication is not
+recognized, you are granted a perpetual, irrevocable license to copy,
+distribute, and modify this file as you see fit.
+
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+// - no 16-bit-per-channel PNG
+// - no 12-bit-per-channel JPEG
+// - no JPEGs with arithmetic coding
+// - no 1-bit BMP
+// - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+// int x,y,n;
+// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+// // ... process data if not NULL ...
+// // ... x = width, y = height, n = # 8-bit components per pixel ...
+// // ... replace '0' with '1'..'4' to force that many components per pixel
+// // ... but 'n' will always be the number that it would have been if you said 0
+// stbi_image_free(data)
+//
+// Standard parameters:
+// int *x -- outputs image width in pixels
+// int *y -- outputs image height in pixels
+// int *comp -- outputs # of image components in image file
+// int req_comp -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
+// If req_comp is non-zero, *comp has the number of components that _would_
+// have been output otherwise. E.g. if you set req_comp to 4, you will always
+// get RGBA output, but you can check *comp to see if it's trivially opaque
+// because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+// N=#comp components
+// 1 grey
+// 2 grey, alpha
+// 3 red, green, blue
+// 4 red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
+// can be queried for an extremely brief, end-user unfriendly explanation
+// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
+// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+// 1. easy to use
+// 2. easy to maintain
+// 3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+// - Portable ("ease of use")
+// - Small footprint ("easy to maintain")
+// - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// The output of the JPEG decoder is slightly different from versions where
+// SIMD support was introduced (that is, for versions before 1.49). The
+// difference is only +-1 in the 8-bit RGB channels, and only on a small
+// fraction of pixels. You can force the pre-1.49 behavior by defining
+// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path
+// and hence cost some performance.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+// stbi_hdr_to_ldr_gamma(2.2f);
+// stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+// float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+// stbi_ldr_to_hdr_scale(1.0f);
+// stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+// stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+ STBI_default = 0, // only used for req_comp
+
+ STBI_grey = 1,
+ STBI_grey_alpha = 2,
+ STBI_rgb = 3,
+ STBI_rgb_alpha = 4
+};
+
+typedef unsigned char stbi_uc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+ int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
+ void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+ int (*eof) (void *user); // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_LINEAR
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
+ STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+ STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+
+ #ifndef STBI_NO_STDIO
+ STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
+ #endif
+#endif
+
+#ifndef STBI_NO_HDR
+ STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
+ STBIDEF void stbi_hdr_to_ldr_scale(float scale);
+#endif
+
+#ifndef STBI_NO_LINEAR
+ STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
+ STBIDEF void stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_HDR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename);
+STBIDEF int stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void stbi_image_free (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+ || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+ || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+ || defined(STBI_ONLY_ZLIB)
+ #ifndef STBI_ONLY_JPEG
+ #define STBI_NO_JPEG
+ #endif
+ #ifndef STBI_ONLY_PNG
+ #define STBI_NO_PNG
+ #endif
+ #ifndef STBI_ONLY_BMP
+ #define STBI_NO_BMP
+ #endif
+ #ifndef STBI_ONLY_PSD
+ #define STBI_NO_PSD
+ #endif
+ #ifndef STBI_ONLY_TGA
+ #define STBI_NO_TGA
+ #endif
+ #ifndef STBI_ONLY_GIF
+ #define STBI_NO_GIF
+ #endif
+ #ifndef STBI_ONLY_HDR
+ #define STBI_NO_HDR
+ #endif
+ #ifndef STBI_ONLY_PIC
+ #define STBI_NO_PIC
+ #endif
+ #ifndef STBI_ONLY_PNM
+ #define STBI_NO_PNM
+ #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h> // ldexp
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+
+#ifndef _MSC_VER
+ #ifdef __cplusplus
+ #define stbi_inline inline
+ #else
+ #define stbi_inline
+ #endif
+#else
+ #define stbi_inline __forceinline
+#endif
+
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef signed short stbi__int16;
+typedef unsigned int stbi__uint32;
+typedef signed int stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v) (void)(v)
+#else
+#define STBI_NOTUSED(v) (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+ #define stbi_lrot(x,y) _lrotl(x,y)
+#else
+ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC)
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz) malloc(sz)
+#define STBI_REALLOC(p,sz) realloc(p,sz)
+#define STBI_FREE(p) free(p)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// NOTE: not clear do we actually need this for the 64-bit path?
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
+// this is just broken and gcc are jerks for not fixing it properly
+// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET)
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400 // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+ int info[4];
+ __cpuid(info,1);
+ return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+ int res;
+ __asm {
+ mov eax,1
+ cpuid
+ mov res,edx
+ }
+ return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+static int stbi__sse2_available()
+{
+ int info3 = stbi__cpuid3();
+ return ((info3 >> 26) & 1) != 0;
+}
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+static int stbi__sse2_available()
+{
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later
+ // GCC 4.8+ has a nice way to do this
+ return __builtin_cpu_supports("sse2");
+#else
+ // portable way to do this, preferably without using GCC inline ASM?
+ // just bail for now.
+ return 0;
+#endif
+}
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+///////////////////////////////////////////////
+//
+// stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+ stbi__uint32 img_x, img_y;
+ int img_n, img_out_n;
+
+ stbi_io_callbacks io;
+ void *io_user_data;
+
+ int read_from_callbacks;
+ int buflen;
+ stbi_uc buffer_start[128];
+
+ stbi_uc *img_buffer, *img_buffer_end;
+ stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+ s->io.read = NULL;
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+ s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+ s->io = *c;
+ s->io_user_data = user;
+ s->buflen = sizeof(s->buffer_start);
+ s->read_from_callbacks = 1;
+ s->img_buffer_original = s->buffer_start;
+ stbi__refill_buffer(s);
+ s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+ return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+ fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stbi__stdio_eof(void *user)
+{
+ return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+ stbi__stdio_read,
+ stbi__stdio_skip,
+ stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+ stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+ // conceptually rewind SHOULD rewind to the beginning of the stream,
+ // but we just rewind to the beginning of the initial buffer, because
+ // we only use it after doing 'test', which only ever looks at at most 92 bytes
+ s->img_buffer = s->img_buffer_original;
+ s->img_buffer_end = s->img_buffer_original_end;
+}
+
+#ifndef STBI_NO_JPEG
+static int stbi__jpeg_test(stbi__context *s);
+static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int stbi__png_test(stbi__context *s);
+static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test(stbi__context *s);
+static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int stbi__tga_test(stbi__context *s);
+static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s);
+static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test(stbi__context *s);
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_test(stbi__context *s);
+static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int stbi__gif_test(stbi__context *s);
+static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int stbi__pnm_test(stbi__context *s);
+static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+// this is not threadsafe
+static const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+ return stbi__g_failure_reason;
+}
+
+static int stbi__err(const char *str)
+{
+ stbi__g_failure_reason = str;
+ return 0;
+}
+
+static void *stbi__malloc(size_t size)
+{
+ return STBI_MALLOC(size);
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+ #define stbi__err(x,y) 0
+#elif defined(STBI_FAILURE_USERMSG)
+ #define stbi__err(x,y) stbi__err(y)
+#else
+ #define stbi__err(x,y) stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+ STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load = flag_true_if_should_flip;
+}
+
+static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_PNG
+ if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_BMP
+ if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_GIF
+ if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_PIC
+ if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp);
+ #endif
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp);
+ #endif
+
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ float *hdr = stbi__hdr_load(s, x,y,comp,req_comp);
+ return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+ }
+ #endif
+
+ #ifndef STBI_NO_TGA
+ // test tga last because it's a crappy test!
+ if (stbi__tga_test(s))
+ return stbi__tga_load(s,x,y,comp,req_comp);
+ #endif
+
+ return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *result = stbi__load_main(s, x, y, comp, req_comp);
+
+ if (stbi__vertically_flip_on_load && result != NULL) {
+ int w = *x, h = *y;
+ int depth = req_comp ? req_comp : *comp;
+ int row,col,z;
+ stbi_uc temp;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < depth; z++) {
+ temp = result[(row * w + col) * depth + z];
+ result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
+ result[((h - row - 1) * w + col) * depth + z] = temp;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+#ifndef STBI_NO_HDR
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+ if (stbi__vertically_flip_on_load && result != NULL) {
+ int w = *x, h = *y;
+ int depth = req_comp ? req_comp : *comp;
+ int row,col,z;
+ float temp;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < depth; z++) {
+ temp = result[(row * w + col) * depth + z];
+ result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
+ result[((h - row - 1) * w + col) * depth + z] = temp;
+ }
+ }
+ }
+ }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+ FILE *f;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != fopen_s(&f, filename, mode))
+ f=0;
+#else
+ f = fopen(filename, mode);
+#endif
+ return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ unsigned char *result;
+ if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_flip(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_flip(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__load_flip(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ unsigned char *data;
+ #ifndef STBI_NO_HDR
+ if (stbi__hdr_test(s)) {
+ float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);
+ if (hdr_data)
+ stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+ return hdr_data;
+ }
+ #endif
+ data = stbi__load_flip(s, x, y, comp, req_comp);
+ if (data)
+ return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+ return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ float *result;
+ FILE *f = stbi__fopen(filename, "rb");
+ if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+ result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(buffer);
+ STBI_NOTUSED(len);
+ return 0;
+ #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_is_hdr (char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result=0;
+ if (f) {
+ result = stbi_is_hdr_from_file(f);
+ fclose(f);
+ }
+ return result;
+}
+
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_file(&s,f);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(f);
+ return 0;
+ #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+ #ifndef STBI_NO_HDR
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+ return stbi__hdr_test(&s);
+ #else
+ STBI_NOTUSED(clbk);
+ STBI_NOTUSED(user);
+ return 0;
+ #endif
+}
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+#ifndef STBI_NO_LINEAR
+STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+ STBI__SCAN_load=0,
+ STBI__SCAN_type,
+ STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+ int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+ if (n == 0) {
+ // at end of file, treat same as if from memory, but need to handle case
+ // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+ s->read_from_callbacks = 0;
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start+1;
+ *s->img_buffer = 0;
+ } else {
+ s->img_buffer = s->buffer_start;
+ s->img_buffer_end = s->buffer_start + n;
+ }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+ if (s->img_buffer < s->img_buffer_end)
+ return *s->img_buffer++;
+ if (s->read_from_callbacks) {
+ stbi__refill_buffer(s);
+ return *s->img_buffer++;
+ }
+ return 0;
+}
+
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+ if (s->io.read) {
+ if (!(s->io.eof)(s->io_user_data)) return 0;
+ // if feof() is true, check if buffer = end
+ // special case: we've only got the special 0 character at the end
+ if (s->read_from_callbacks == 0) return 1;
+ }
+
+ return s->img_buffer >= s->img_buffer_end;
+}
+
+static void stbi__skip(stbi__context *s, int n)
+{
+ if (n < 0) {
+ s->img_buffer = s->img_buffer_end;
+ return;
+ }
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ s->img_buffer = s->img_buffer_end;
+ (s->io.skip)(s->io_user_data, n - blen);
+ return;
+ }
+ }
+ s->img_buffer += n;
+}
+
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+ if (s->io.read) {
+ int blen = (int) (s->img_buffer_end - s->img_buffer);
+ if (blen < n) {
+ int res, count;
+
+ memcpy(buffer, s->img_buffer, blen);
+
+ count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+ res = (count == (n-blen));
+ s->img_buffer = s->img_buffer_end;
+ return res;
+ }
+ }
+
+ if (s->img_buffer+n <= s->img_buffer_end) {
+ memcpy(buffer, s->img_buffer, n);
+ s->img_buffer += n;
+ return 1;
+ } else
+ return 0;
+}
+
+static int stbi__get16be(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return (z << 8) + stbi__get8(s);
+}
+
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16be(s);
+ return (z << 16) + stbi__get16be(s);
+}
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+ int z = stbi__get8(s);
+ return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+ stbi__uint32 z = stbi__get16le(s);
+ return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// generic converter from built-in img_n to req_comp
+// individual types do this automatically as much as possible (e.g. jpeg
+// does all cases internally since it needs to colorspace convert anyway,
+// and it never has alpha, so very few cases ). png can automatically
+// interleave an alpha=255 channel, but falls back to this for other cases
+//
+// assume data buffer is malloced, so malloc a new one and free that one
+// only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+ return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ unsigned char *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (unsigned char *) stbi__malloc(req_comp * x * y);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ unsigned char *src = data + j * x * img_n ;
+ unsigned char *dest = good + j * x * req_comp;
+
+ #define COMBO(a,b) ((a)*8+(b))
+ #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (COMBO(img_n, req_comp)) {
+ CASE(1,2) dest[0]=src[0], dest[1]=255; break;
+ CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+ CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;
+ CASE(2,1) dest[0]=src[0]; break;
+ CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+ CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;
+ CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;
+ CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
+ CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break;
+ CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
+ CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;
+ CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;
+ default: STBI_ASSERT(0);
+ }
+ #undef CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+ int i,k,n;
+ float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));
+ if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+ }
+ if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x) ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
+{
+ int i,k,n;
+ stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);
+ if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+ // compute number of non-alpha components
+ if (comp & 1) n = comp; else n = comp-1;
+ for (i=0; i < x*y; ++i) {
+ for (k=0; k < n; ++k) {
+ float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ if (k < comp) {
+ float z = data[i*comp+k] * 255 + 0.5f;
+ if (z < 0) z = 0;
+ if (z > 255) z = 255;
+ output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+ }
+ }
+ STBI_FREE(data);
+ return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// "baseline" JPEG/JFIF decoder
+//
+// simple implementation
+// - doesn't support delayed output of y-dimension
+// - simple interface (only one output format: 8-bit interleaved RGB)
+// - doesn't try to recover corrupt jpegs
+// - doesn't allow partial loading, loading multiple at once
+// - still fast on x86 (copying globals into locals doesn't help x86)
+// - allocates lots of intermediate memory (full size of all components)
+// - non-interleaved case requires this anyway
+// - allows good upsampling (see next)
+// high-quality
+// - upsampled channels are bilinearly interpolated, even across blocks
+// - quality integer IDCT derived from IJG's 'slow'
+// performance
+// - fast huffman; reasonable integer IDCT
+// - some SIMD kernels for common paths on targets with SSE2/NEON
+// - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+ stbi_uc fast[1 << FAST_BITS];
+ // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+ stbi__uint16 code[256];
+ stbi_uc values[256];
+ stbi_uc size[257];
+ unsigned int maxcode[18];
+ int delta[17]; // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+ stbi__context *s;
+ stbi__huffman huff_dc[4];
+ stbi__huffman huff_ac[4];
+ stbi_uc dequant[4][64];
+ stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+ int img_h_max, img_v_max;
+ int img_mcu_x, img_mcu_y;
+ int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+ struct
+ {
+ int id;
+ int h,v;
+ int tq;
+ int hd,ha;
+ int dc_pred;
+
+ int x,y,w2,h2;
+ stbi_uc *data;
+ void *raw_data, *raw_coeff;
+ stbi_uc *linebuf;
+ short *coeff; // progressive only
+ int coeff_w, coeff_h; // number of 8x8 coefficient blocks
+ } img_comp[4];
+
+ stbi__uint32 code_buffer; // jpeg entropy-coded buffer
+ int code_bits; // number of valid bits
+ unsigned char marker; // marker seen while filling entropy buffer
+ int nomore; // flag if we saw a marker so must stop
+
+ int progressive;
+ int spec_start;
+ int spec_end;
+ int succ_high;
+ int succ_low;
+ int eob_run;
+
+ int scan_n, order[4];
+ int restart_interval, todo;
+
+// kernels
+ void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+ void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+ stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+ int i,j,k=0,code;
+ // build size list for each symbol (from JPEG spec)
+ for (i=0; i < 16; ++i)
+ for (j=0; j < count[i]; ++j)
+ h->size[k++] = (stbi_uc) (i+1);
+ h->size[k] = 0;
+
+ // compute actual symbols (from jpeg spec)
+ code = 0;
+ k = 0;
+ for(j=1; j <= 16; ++j) {
+ // compute delta to add to code to compute symbol id
+ h->delta[j] = k - code;
+ if (h->size[k] == j) {
+ while (h->size[k] == j)
+ h->code[k++] = (stbi__uint16) (code++);
+ if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+ }
+ // compute largest code + 1 for this size, preshifted as needed later
+ h->maxcode[j] = code << (16-j);
+ code <<= 1;
+ }
+ h->maxcode[j] = 0xffffffff;
+
+ // build non-spec acceleration table; 255 is flag for not-accelerated
+ memset(h->fast, 255, 1 << FAST_BITS);
+ for (i=0; i < k; ++i) {
+ int s = h->size[i];
+ if (s <= FAST_BITS) {
+ int c = h->code[i] << (FAST_BITS-s);
+ int m = 1 << (FAST_BITS-s);
+ for (j=0; j < m; ++j) {
+ h->fast[c+j] = (stbi_uc) i;
+ }
+ }
+ }
+ return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+ int i;
+ for (i=0; i < (1 << FAST_BITS); ++i) {
+ stbi_uc fast = h->fast[i];
+ fast_ac[i] = 0;
+ if (fast < 255) {
+ int rs = h->values[fast];
+ int run = (rs >> 4) & 15;
+ int magbits = rs & 15;
+ int len = h->size[fast];
+
+ if (magbits && len + magbits <= FAST_BITS) {
+ // magnitude code followed by receive_extend code
+ int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+ int m = 1 << (magbits - 1);
+ if (k < m) k += (-1 << magbits) + 1;
+ // if the result is small enough, we can fit it in fast_ac table
+ if (k >= -128 && k <= 127)
+ fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+ }
+ }
+ }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+ do {
+ int b = j->nomore ? 0 : stbi__get8(j->s);
+ if (b == 0xff) {
+ int c = stbi__get8(j->s);
+ if (c != 0) {
+ j->marker = (unsigned char) c;
+ j->nomore = 1;
+ return;
+ }
+ }
+ j->code_buffer |= b << (24 - j->code_bits);
+ j->code_bits += 8;
+ } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+ unsigned int temp;
+ int c,k;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ // look at the top FAST_BITS and determine what symbol ID it is,
+ // if the code is <= FAST_BITS
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ k = h->fast[c];
+ if (k < 255) {
+ int s = h->size[k];
+ if (s > j->code_bits)
+ return -1;
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ return h->values[k];
+ }
+
+ // naive test is to shift the code_buffer down so k bits are
+ // valid, then test against maxcode. To speed this up, we've
+ // preshifted maxcode left so that it has (16-k) 0s at the
+ // end; in other words, regardless of the number of bits, it
+ // wants to be compared against something shifted to have 16;
+ // that way we don't need to shift inside the loop.
+ temp = j->code_buffer >> 16;
+ for (k=FAST_BITS+1 ; ; ++k)
+ if (temp < h->maxcode[k])
+ break;
+ if (k == 17) {
+ // error! code not found
+ j->code_bits -= 16;
+ return -1;
+ }
+
+ if (k > j->code_bits)
+ return -1;
+
+ // convert the huffman code to the symbol id
+ c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+ STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+ // convert the id to a symbol
+ j->code_bits -= k;
+ j->code_buffer <<= k;
+ return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ int sgn;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+ sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+ k = stbi_lrot(j->code_buffer, n);
+ STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+ k = stbi_lrot(j->code_buffer, n);
+ j->code_buffer = k & ~stbi__bmask[n];
+ k &= stbi__bmask[n];
+ j->code_bits -= n;
+ return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+ unsigned int k;
+ if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+ k = j->code_buffer;
+ j->code_buffer <<= 1;
+ --j->code_bits;
+ return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ // let corrupt input sample past end
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant)
+{
+ int diff,dc,k;
+ int t;
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ t = stbi__jpeg_huff_decode(j, hdc);
+ if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+ // 0 all the ac values now so we can do it 32-bits at a time
+ memset(data,0,64*sizeof(data[0]));
+
+ diff = t ? stbi__extend_receive(j, t) : 0;
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc * dequant[0]);
+
+ // decode AC components, see JPEG spec
+ k = 1;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) * dequant[zig]);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (rs != 0xf0) break; // end block
+ k += 16;
+ } else {
+ k += r;
+ // decode into unzigzag'd location
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+ }
+ }
+ } while (k < 64);
+ return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+ int diff,dc;
+ int t;
+ if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+ if (j->succ_high == 0) {
+ // first scan for DC coefficient, must be first
+ memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+ t = stbi__jpeg_huff_decode(j, hdc);
+ diff = t ? stbi__extend_receive(j, t) : 0;
+
+ dc = j->img_comp[b].dc_pred + diff;
+ j->img_comp[b].dc_pred = dc;
+ data[0] = (short) (dc << j->succ_low);
+ } else {
+ // refinement scan for DC coefficient
+ if (stbi__jpeg_get_bit(j))
+ data[0] += (short) (1 << j->succ_low);
+ }
+ return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+ int k;
+ if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+ if (j->succ_high == 0) {
+ int shift = j->succ_low;
+
+ if (j->eob_run) {
+ --j->eob_run;
+ return 1;
+ }
+
+ k = j->spec_start;
+ do {
+ unsigned int zig;
+ int c,r,s;
+ if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+ c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+ r = fac[c];
+ if (r) { // fast-AC path
+ k += (r >> 4) & 15; // run
+ s = r & 15; // combined length
+ j->code_buffer <<= s;
+ j->code_bits -= s;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) ((r >> 8) << shift);
+ } else {
+ int rs = stbi__jpeg_huff_decode(j, hac);
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r);
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ --j->eob_run;
+ break;
+ }
+ k += 16;
+ } else {
+ k += r;
+ zig = stbi__jpeg_dezigzag[k++];
+ data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+ }
+ }
+ } while (k <= j->spec_end);
+ } else {
+ // refinement scan for these AC coefficients
+
+ short bit = (short) (1 << j->succ_low);
+
+ if (j->eob_run) {
+ --j->eob_run;
+ for (k = j->spec_start; k <= j->spec_end; ++k) {
+ short *p = &data[stbi__jpeg_dezigzag[k]];
+ if (*p != 0)
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ }
+ } else {
+ k = j->spec_start;
+ do {
+ int r,s;
+ int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+ if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ s = rs & 15;
+ r = rs >> 4;
+ if (s == 0) {
+ if (r < 15) {
+ j->eob_run = (1 << r) - 1;
+ if (r)
+ j->eob_run += stbi__jpeg_get_bits(j, r);
+ r = 64; // force end of block
+ } else {
+ // r=15 s=0 should write 16 0s, so we just do
+ // a run of 15 0s and then write s (which is 0),
+ // so we don't have to do anything special here
+ }
+ } else {
+ if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+ // sign bit
+ if (stbi__jpeg_get_bit(j))
+ s = bit;
+ else
+ s = -bit;
+ }
+
+ // advance by r
+ while (k <= j->spec_end) {
+ short *p = &data[stbi__jpeg_dezigzag[k++]];
+ if (*p != 0) {
+ if (stbi__jpeg_get_bit(j))
+ if ((*p & bit)==0) {
+ if (*p > 0)
+ *p += bit;
+ else
+ *p -= bit;
+ }
+ } else {
+ if (r == 0) {
+ *p = (short) s;
+ break;
+ }
+ --r;
+ }
+ }
+ } while (k <= j->spec_end);
+ }
+ }
+ return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+ // trick to use a single test to catch both cases
+ if ((unsigned int) x > 255) {
+ if (x < 0) return 0;
+ if (x > 255) return 255;
+ }
+ return (stbi_uc) x;
+}
+
+#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x) ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+ p2 = s2; \
+ p3 = s6; \
+ p1 = (p2+p3) * stbi__f2f(0.5411961f); \
+ t2 = p1 + p3*stbi__f2f(-1.847759065f); \
+ t3 = p1 + p2*stbi__f2f( 0.765366865f); \
+ p2 = s0; \
+ p3 = s4; \
+ t0 = stbi__fsh(p2+p3); \
+ t1 = stbi__fsh(p2-p3); \
+ x0 = t0+t3; \
+ x3 = t0-t3; \
+ x1 = t1+t2; \
+ x2 = t1-t2; \
+ t0 = s7; \
+ t1 = s5; \
+ t2 = s3; \
+ t3 = s1; \
+ p3 = t0+t2; \
+ p4 = t1+t3; \
+ p1 = t0+t3; \
+ p2 = t1+t2; \
+ p5 = (p3+p4)*stbi__f2f( 1.175875602f); \
+ t0 = t0*stbi__f2f( 0.298631336f); \
+ t1 = t1*stbi__f2f( 2.053119869f); \
+ t2 = t2*stbi__f2f( 3.072711026f); \
+ t3 = t3*stbi__f2f( 1.501321110f); \
+ p1 = p5 + p1*stbi__f2f(-0.899976223f); \
+ p2 = p5 + p2*stbi__f2f(-2.562915447f); \
+ p3 = p3*stbi__f2f(-1.961570560f); \
+ p4 = p4*stbi__f2f(-0.390180644f); \
+ t3 += p1+p4; \
+ t2 += p2+p3; \
+ t1 += p2+p4; \
+ t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+ int i,val[64],*v=val;
+ stbi_uc *o;
+ short *d = data;
+
+ // columns
+ for (i=0; i < 8; ++i,++d, ++v) {
+ // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+ if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+ && d[40]==0 && d[48]==0 && d[56]==0) {
+ // no shortcut 0 seconds
+ // (1|2|3|4|5|6|7)==0 0 seconds
+ // all separate -0.047 seconds
+ // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
+ int dcterm = d[0] << 2;
+ v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+ } else {
+ STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+ // constants scaled things up by 1<<12; let's bring them back
+ // down, but keep 2 extra bits of precision
+ x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+ v[ 0] = (x0+t3) >> 10;
+ v[56] = (x0-t3) >> 10;
+ v[ 8] = (x1+t2) >> 10;
+ v[48] = (x1-t2) >> 10;
+ v[16] = (x2+t1) >> 10;
+ v[40] = (x2-t1) >> 10;
+ v[24] = (x3+t0) >> 10;
+ v[32] = (x3-t0) >> 10;
+ }
+ }
+
+ for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+ // no fast case since the first 1D IDCT spread components out
+ STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+ // constants scaled things up by 1<<12, plus we had 1<<2 from first
+ // loop, plus horizontal and vertical each scale by sqrt(8) so together
+ // we've got an extra 1<<3, so 1<<17 total we need to remove.
+ // so we want to round that, which means adding 0.5 * 1<<17,
+ // aka 65536. Also, we'll end up with -128 to 127 that we want
+ // to encode as 0..255 by adding 128, so we'll add that before the shift
+ x0 += 65536 + (128<<17);
+ x1 += 65536 + (128<<17);
+ x2 += 65536 + (128<<17);
+ x3 += 65536 + (128<<17);
+ // tried computing the shifts into temps, or'ing the temps to see
+ // if any were out of range, but that was slower
+ o[0] = stbi__clamp((x0+t3) >> 17);
+ o[7] = stbi__clamp((x0-t3) >> 17);
+ o[1] = stbi__clamp((x1+t2) >> 17);
+ o[6] = stbi__clamp((x1-t2) >> 17);
+ o[2] = stbi__clamp((x2+t1) >> 17);
+ o[5] = stbi__clamp((x2-t1) >> 17);
+ o[3] = stbi__clamp((x3+t0) >> 17);
+ o[4] = stbi__clamp((x3-t0) >> 17);
+ }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+ // This is constructed to match our regular (generic) integer IDCT exactly.
+ __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+ __m128i tmp;
+
+ // dot product constant: even elems=x, odd elems=y
+ #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+ // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit)
+ // out(1) = c1[even]*x + c1[odd]*y
+ #define dct_rot(out0,out1, x,y,c0,c1) \
+ __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+ __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+ __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+ __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+ __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+ __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+ // out = in << 12 (in 16-bit, out 32-bit)
+ #define dct_widen(out, in) \
+ __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+ __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+ // wide add
+ #define dct_wadd(out, a, b) \
+ __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+ // wide sub
+ #define dct_wsub(out, a, b) \
+ __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+ __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+ // butterfly a/b, add bias, then shift by "s" and pack
+ #define dct_bfly32o(out0, out1, a,b,bias,s) \
+ { \
+ __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+ __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+ dct_wadd(sum, abiased, b); \
+ dct_wsub(dif, abiased, b); \
+ out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+ out1