aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml72
-rw-r--r--Abel-Regular.ttfbin0 -> 35220 bytes
-rw-r--r--README.md38
-rw-r--r--VERSION1
-rw-r--r--audio.pngbin0 -> 639 bytes
-rwxr-xr-xdocker_build.sh24
-rwxr-xr-xdocker_run.sh5
-rw-r--r--manifest.ttl.in34
-rw-r--r--meson.build111
-rw-r--r--meson/arm-linux-gnueabihf18
-rw-r--r--meson/i686-linux-gnu19
-rw-r--r--meson/i686-w64-mingw3217
-rw-r--r--meson/universal-apple-darwin19
-rw-r--r--meson/x86_64-linux-gnu16
-rw-r--r--meson/x86_64-w64-mingw3217
-rw-r--r--midi.pngbin0 -> 1011 bytes
-rw-r--r--nk_pugl/COPYING201
-rw-r--r--nk_pugl/nk_pugl.h (renamed from nk_pugl.h)0
-rw-r--r--nuk.c167
-rw-r--r--nuk.h32
-rw-r--r--nuk.ttl372
-rw-r--r--nuk_ui.c731
-rw-r--r--nuk_ui.ttl32
-rw-r--r--nuklear/.gitattributes3
-rw-r--r--nuklear/.gitignore8
-rw-r--r--nuklear/.gitmodules0
-rw-r--r--nuklear/.travis.yml16
-rw-r--r--nuklear/Readme.md165
-rw-r--r--nuklear/demo/allegro5/KeyboardHandleriOS.h10
-rw-r--r--nuklear/demo/allegro5/KeyboardHandleriOS.m120
-rw-r--r--nuklear/demo/allegro5/Makefile22
-rw-r--r--nuklear/demo/allegro5/Readme.md35
-rw-r--r--nuklear/demo/allegro5/main.c165
-rw-r--r--nuklear/demo/allegro5/nuklear_allegro5.h459
-rw-r--r--nuklear/demo/calculator.c64
-rw-r--r--nuklear/demo/d3d11/build.bat9
-rw-r--r--nuklear/demo/d3d11/main.c299
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11.h622
-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/d3d9/build.bat6
-rw-r--r--nuklear/demo/d3d9/main.c313
-rw-r--r--nuklear/demo/d3d9/nuklear_d3d9.h543
-rw-r--r--nuklear/demo/gdi/build.bat6
-rw-r--r--nuklear/demo/gdi/main.c184
-rw-r--r--nuklear/demo/gdi/nuklear_gdi.h842
-rw-r--r--nuklear/demo/gdip/build.bat5
-rw-r--r--nuklear/demo/gdip/main.c178
-rw-r--r--nuklear/demo/gdip/nuklear_gdip.h1175
-rw-r--r--nuklear/demo/glfw_opengl2/Makefile25
-rw-r--r--nuklear/demo/glfw_opengl2/main.c182
-rw-r--r--nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h381
-rw-r--r--nuklear/demo/glfw_opengl3/Makefile26
-rw-r--r--nuklear/demo/glfw_opengl3/main.c200
-rw-r--r--nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h492
-rw-r--r--nuklear/demo/node_editor.c343
-rw-r--r--nuklear/demo/overview.c1249
-rw-r--r--nuklear/demo/sdl_opengl2/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl2/main.c198
-rw-r--r--nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h346
-rw-r--r--nuklear/demo/sdl_opengl3/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl3/main.c208
-rw-r--r--nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h442
-rw-r--r--nuklear/demo/sdl_opengles2/Makefile25
-rw-r--r--nuklear/demo/sdl_opengles2/main.c191
-rw-r--r--nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h443
-rw-r--r--nuklear/demo/sfml_opengl2/Makefile33
-rw-r--r--nuklear/demo/sfml_opengl2/Readme.md9
-rw-r--r--nuklear/demo/sfml_opengl2/main.cpp181
-rw-r--r--nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h359
-rw-r--r--nuklear/demo/sfml_opengl3/Makefile37
-rw-r--r--nuklear/demo/sfml_opengl3/Readme.md11
-rw-r--r--nuklear/demo/sfml_opengl3/main.cpp189
-rw-r--r--nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h463
-rw-r--r--nuklear/demo/style.c132
-rw-r--r--nuklear/demo/x11/Makefile13
-rw-r--r--nuklear/demo/x11/main.c224
-rw-r--r--nuklear/demo/x11/nuklear_xlib.h957
-rw-r--r--nuklear/demo/x11_opengl2/Makefile26
-rw-r--r--nuklear/demo/x11_opengl2/main.c345
-rw-r--r--nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h376
-rw-r--r--nuklear/demo/x11_opengl3/Makefile26
-rw-r--r--nuklear/demo/x11_opengl3/main.c342
-rw-r--r--nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h743
-rw-r--r--nuklear/demo/x11_rawfb/Makefile13
-rw-r--r--nuklear/demo/x11_rawfb/main.c263
-rw-r--r--nuklear/demo/x11_rawfb/nuklear_rawfb.h986
-rw-r--r--nuklear/demo/x11_rawfb/nuklear_xlib.h283
-rw-r--r--nuklear/doc/Makefile24
-rwxr-xr-xnuklear/doc/build.sh4
-rw-r--r--nuklear/doc/nuklear.html2533
-rw-r--r--nuklear/doc/stddoc.c141
-rw-r--r--nuklear/example/Makefile42
-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.c824
-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.h25596
-rw-r--r--nuklear/package.json8
-rw-r--r--pugl/.gitignore3
-rw-r--r--pugl/AUTHORS11
-rw-r--r--pugl/COPYING13
-rw-r--r--pugl/Doxyfile.in2415
-rw-r--r--pugl/README.md28
-rw-r--r--pugl/pugl.pc.in10
-rw-r--r--pugl/pugl/cairo_gl.h105
-rw-r--r--pugl/pugl/gl.h32
-rw-r--r--pugl/pugl/glew.h32
-rw-r--r--pugl/pugl/glu.h32
-rw-r--r--pugl/pugl/pugl.h634
-rw-r--r--pugl/pugl/pugl.hpp108
-rw-r--r--pugl/pugl/pugl_internal.h273
-rw-r--r--pugl/pugl/pugl_osx.m752
-rw-r--r--pugl/pugl/pugl_win.cpp704
-rw-r--r--pugl/pugl/pugl_x11.c811
-rw-r--r--pugl/pugl_cairo_test.c205
-rw-r--r--pugl/pugl_test.c261
-rwxr-xr-xpugl/wafbin0 -> 97489 bytes
-rw-r--r--pugl/wscript203
172 files changed, 63170 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..a4cf5b1
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,72 @@
+stages:
+ - build
+ - test
+ - deploy
+
+.variables_template: &variables_definition
+ variables:
+ BASE_NAME: "nuk.lv2"
+ PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig"
+ TOOLCHAIN_FILE: "meson/${CI_BUILD_NAME}"
+
+.common_template: &common_definition
+ <<: *variables_definition
+ stage: build
+ artifacts:
+ name: "${BASE_NAME}-$(cat VERSION)-${CI_BUILD_NAME}"
+ paths:
+ - "${BASE_NAME}-$(cat VERSION)/"
+
+.build_template: &build_definition
+ <<: *common_definition
+ script:
+ - meson --prefix="/opt/${CI_BUILD_NAME}" --libdir="lib" --cross-file "${TOOLCHAIN_FILE}" build
+ - ninja -C build
+ - ninja -C build install
+ - mkdir -p "${BASE_NAME}-$(cat VERSION)/${CI_BUILD_NAME}/${BASE_NAME}"
+ - cp -r "/opt/${CI_BUILD_NAME}/lib/lv2/${BASE_NAME}/" "${BASE_NAME}-$(cat VERSION)/${CI_BUILD_NAME}/"
+
+.universal_linux_template: &universal_linux_definition
+ image: ventosus/universal-linux-gnu
+ <<: *build_definition
+
+.arm_linux_template: &arm_linux_definition
+ image: ventosus/arm-linux-gnueabihf
+ <<: *build_definition
+
+.universal_w64_template: &universal_w64_definition
+ image: ventosus/universal-w64-mingw32
+ <<: *build_definition
+
+.universal_apple_template: &universal_apple_definition
+ image: ventosus/universal-apple-darwin
+ <<: *build_definition
+
+# building in docker
+x86_64-linux-gnu:
+ <<: *universal_linux_definition
+
+i686-linux-gnu:
+ <<: *universal_linux_definition
+
+arm-linux-gnueabihf:
+ <<: *arm_linux_definition
+
+x86_64-w64-mingw32:
+ <<: *universal_w64_definition
+
+i686-w64-mingw32:
+ <<: *universal_w64_definition
+
+universal-apple-darwin:
+ <<: *universal_apple_definition
+
+pack:
+ <<: *variables_definition
+ stage: deploy
+ script:
+ - echo 'packing up...'
+ artifacts:
+ name: "${BASE_NAME}-$(cat VERSION)"
+ paths:
+ - "${BASE_NAME}-$(cat VERSION)/"
diff --git a/Abel-Regular.ttf b/Abel-Regular.ttf
new file mode 100644
index 0000000..0cf6f33
--- /dev/null
+++ b/Abel-Regular.ttf
Binary files differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f3b2ee2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# nuk.lv2
+
+## Example LV2 plugin bundle for the nuklear GUI
+
+
+### Build status
+
+[![build status](https://gitlab.com/OpenMusicKontrollers/nuk.lv2/badges/master/build.svg)](https://gitlab.com/OpenMusicKontrollers/nuk.lv2/commits/master)
+
+### Dependencies
+
+* [LV2](http://lv2plug.in) (LV2 Plugin Standard)
+
+### Build / install
+
+ git clone https://git.open-music-kontrollers.ch/lv2//nuk.lv2.git
+ cd nuk.lv2
+ meson build
+ cd build
+ ninja -j4
+ sudo ninja install
+
+### License
+
+Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+
+This is free software: you can redistribute it and/or modify
+it under the terms of the Artistic License 2.0 as published by
+The Perl Foundation.
+
+This source is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+Artistic License 2.0 for more details.
+
+You should have received a copy of the Artistic License 2.0
+along the source as a COPYING file. If not, obtain it from
+<http://www.perlfoundation.org/artistic_license_2_0>.
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..d6cb952
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.1.2917
diff --git a/audio.png b/audio.png
new file mode 100644
index 0000000..c244fee
--- /dev/null
+++ b/audio.png
Binary files differ
diff --git a/docker_build.sh b/docker_build.sh
new file mode 100755
index 0000000..de81093
--- /dev/null
+++ b/docker_build.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+TARGET=$1
+
+CI_PROJECT_DIR=$(pwd)
+CI_BUILD_NAME=${TARGET}
+
+BASE_NAME="nuk.lv2"
+PKG_CONFIG_PATH="/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig"
+TOOLCHAIN_FILE="${CI_PROJECT_DIR}/cmake/${CI_BUILD_NAME}.cmake"
+
+rm -rf ${TARGET}
+mkdir -p ${TARGET}
+pushd ${TARGET}
+ PKG_CONFIG_PATH=${PKG_CONFIG_PATH} cmake \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR} \
+ -DPLUGIN_DEST="${BASE_NAME}-$(cat ../VERSION)/${CI_BUILD_NAME}/${BASE_NAME}" \
+ -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} \
+ ..
+ make -j4
+ make install
+ #ARGS='-VV' make test
+popd
diff --git a/docker_run.sh b/docker_run.sh
new file mode 100755
index 0000000..b79ca0d
--- /dev/null
+++ b/docker_run.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/bash
+
+TARGET=$1
+
+docker run --rm -it -v $(pwd):/workdir/nuk.lv2 ventosus/${TARGET}
diff --git a/manifest.ttl.in b/manifest.ttl.in
new file mode 100644
index 0000000..4f50e95
--- /dev/null
+++ b/manifest.ttl.in
@@ -0,0 +1,34 @@
+# Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+#
+# This is free software: you can redistribute it and/or modify
+# it under the terms of the Artistic License 2.0 as published by
+# The Perl Foundation.
+#
+# This source is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Artistic License 2.0 for more details.
+#
+# You should have received a copy of the Artistic License 2.0
+# along the source as a COPYING file. If not, obtain it from
+# http://www.perlfoundation.org/artistic_license_2_0.
+
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix owl: <http://www.w3.org/2002/07/owl#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+
+@prefix nuk: <http://open-music-kontrollers.ch/lv2/nuk#> .
+
+nuk:nuk
+ a lv2:Plugin ;
+ lv2:minorVersion @MINOR_VERSION@ ;
+ lv2:microVersion @MICRO_VERSION@ ;
+ lv2:binary <nuk@MODULE_SUFFIX@> ;
+ ui:ui nuk:nuk_ui ;
+ rdfs:seeAlso <nuk.ttl> .
+
+nuk:nuk_ui
+ a ui:@UI_TYPE@ ;
+ ui:binary <nuk_ui@MODULE_SUFFIX@> ;
+ rdfs:seeAlso <nuk_ui.ttl> .
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..3ae349e
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,111 @@
+project('nuk.lv2', 'c', default_options : [
+ 'buildtype=release',
+ 'warning_level=1',
+ 'werror=false',
+ 'b_lto=false',
+ 'c_std=c11'])
+
+cc = meson.get_compiler('c')
+
+m_dep = cc.find_library('m')
+lv2_dep = dependency('lv2', version : '>=1.14.0')
+
+dsp_deps = [m_dep, lv2_dep]
+ui_deps = [m_dep, lv2_dep]
+
+pugl_inc = include_directories('pugl')
+inc_dir = [pugl_inc]
+
+inst_dir = join_paths(get_option('libdir'), 'lv2', meson.project_name())
+
+rawvers = run_command('cat', 'VERSION').stdout().strip()
+version = rawvers.split('.')
+
+conf_data = configuration_data()
+conf_data.set('MAJOR_VERSION', version[0])
+conf_data.set('MINOR_VERSION', version[1])
+conf_data.set('MICRO_VERSION', version[2])
+
+add_project_arguments('-DNUK_VERSION="'+rawvers+'"', language : 'c')
+add_project_arguments('-D_GNU_SOURCE', language : 'c')
+add_project_arguments('-DPUGL_HAVE_GL', language : 'c')
+
+cp = find_program('cp')
+clone = [cp, '@INPUT@', '@OUTPUT@']
+
+c_args = ['-fvisibility=hidden',
+ '-ffast-math',
+ '-Wno-unused-variable',
+ '-Wno-unused-function',
+ '-Wno-misleading-indentation']
+
+dsp_srcs = ['nuk.c']
+
+ui_srcs = ['nuk_ui.c']
+
+if host_machine.system() == 'linux'
+ conf_data.set('UI_TYPE', 'X11UI')
+ ui_deps += dependency('gl')
+ ui_deps += dependency('x11', version : '>=1.6.0')
+ ui_deps += dependency('xext', version : '>=1.3.0')
+ ui_srcs += 'pugl/pugl/pugl_x11.c'
+elif host_machine.system() == 'windows'
+ add_languages('cpp')
+ conf_data.set('UI_TYPE', 'WindowsUI')
+ ui_deps += cc.find_library('opengl32')
+ ui_deps += cc.find_library('gdi32')
+ ui_deps += cc.find_library('user32')
+ ui_srcs += 'pugl/pugl/pugl_win.cpp'
+elif host_machine.system() == 'darwin'
+ #add_languages('objc')
+ conf_data.set('UI_TYPE', 'CocoaUI')
+ #ui_deps += cc.find_library('Cocoa')
+ #ui_deps += cc.find_library('gl')
+ #ui_deps += dependency('appleframeworks', modules : 'cocoa')
+ #ui_srcs += 'pugl/pugl/pugl_osx.m'
+endif
+
+mod = shared_module('nuk', dsp_srcs,
+ c_args : c_args,
+ include_directories : inc_dir,
+ name_prefix : '',
+ dependencies : dsp_deps,
+ install : true,
+ install_dir : inst_dir)
+
+ui = shared_module('nuk_ui', ui_srcs,
+ c_args : c_args,
+ include_directories : inc_dir,
+ name_prefix : '',
+ dependencies : ui_deps,
+ install : true,
+ install_dir : inst_dir)
+
+suffix = mod.full_path().strip().split('.')[-1]
+conf_data.set('MODULE_SUFFIX', '.' + suffix)
+
+configure_file(input : 'manifest.ttl.in', output : 'manifest.ttl',
+ configuration : conf_data,
+ install : true,
+ install_dir : inst_dir)
+
+custom_target('dsp_ttl',
+ input : 'nuk.ttl',
+ output : 'nuk.ttl',
+ command : clone,
+ install : true,
+ install_dir : inst_dir)
+
+custom_target('ui_ttl',
+ input : 'nuk_ui.ttl',
+ output : 'nuk_ui.ttl',
+ command : clone,
+ install : true,
+ install_dir : inst_dir)
+
+custom_target('font',
+ input : 'Abel-Regular.ttf',
+ output : 'Abel-Regular.ttf',
+ command : clone,
+ install : true,
+ install_dir : inst_dir)
diff --git a/meson/arm-linux-gnueabihf b/meson/arm-linux-gnueabihf
new file mode 100644
index 0000000..241266e
--- /dev/null
+++ b/meson/arm-linux-gnueabihf
@@ -0,0 +1,18 @@
+[host_machine]
+system = 'linux'
+cpu_family = 'arm'
+cpu = 'armv7hl'
+endian = 'little'
+
+[binaries]
+c = '/usr/bin/arm-linux-gnueabihf-gcc'
+cpp = '/usr/bin/arm-linux-gnueabihf-g++'
+ar = '/usr/bin/arm-linux-gnueabihf-ar'
+strip = '/usr/bin/arm-linux-gnueabihf-strip'
+pkgconfig = '/usr/bin/pkg-config'
+exe_wrapper = '/usr/bin/qemu-arm'
+
+[properties]
+root = '/usr/arm-linux-gnueabihf'
+c_link_args = ['-Wl,-z,defs']
+needs_exe_wrapper = true
diff --git a/meson/i686-linux-gnu b/meson/i686-linux-gnu
new file mode 100644
index 0000000..17d5a41
--- /dev/null
+++ b/meson/i686-linux-gnu
@@ -0,0 +1,19 @@
+[host_machine]
+system = 'linux'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
+
+[binaries]
+c = '/usr/bin/x86_64-linux-gnu-gcc'
+cpp = '/usr/bin/x86_64-linux-gnu-g++'
+ar = '/usr/bin/x86_64-linux-gnu-ar'
+strip = '/usr/bin/x86_64-linux-gnu-strip'
+pkgconfig = '/usr/bin/pkg-config'
+
+[properties]
+c_args = ['-m32']
+cpp_args = ['-m32']
+c_link_args = ['-m32', '-Wl,-z,defs']
+cpp_link_args = ['-m32', '-Wl,-z,defs']
+needs_exe_wrapper = false
diff --git a/meson/i686-w64-mingw32 b/meson/i686-w64-mingw32
new file mode 100644
index 0000000..4966ba7
--- /dev/null
+++ b/meson/i686-w64-mingw32
@@ -0,0 +1,17 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'i686'
+cpu = 'i686'
+endian = 'little'
+
+[binaries]
+c = '/usr/bin/i686-w64-mingw32-gcc'
+cpp = '/usr/bin/i686-w64-mingw32-g++'
+ar = '/usr/bin/i686-w64-mingw32-ar'
+strip = '/usr/bin/i686-w64-mingw32-strip'
+pkgconfig = '/usr/bin/pkg-config'
+exe_wrapper = '/usr/bin/wine'
+
+[properties]
+root = '/usr/i686-w64-mingw32'
+needs_exe_wrapper = true
diff --git a/meson/universal-apple-darwin b/meson/universal-apple-darwin
new file mode 100644
index 0000000..0ee2e02
--- /dev/null
+++ b/meson/universal-apple-darwin
@@ -0,0 +1,19 @@
+[host_machine]
+system = 'darwin'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[binaries]
+c = '/usr/universal-apple-darwin/bin/x86_64-apple-darwin15-clang'
+cpp = '/usr/universal-apple-darwin/bin/x86_64-apple-darwin15-clang++'
+objc = '/usr/universal-apple-darwin/bin/x86_64-apple-darwin15-clang'
+ar = '/usr/universal-apple-darwin/bin/x86_64-apple-darwin15-ar'
+strip = '/usr/universal-apple-darwin/bin/x86_64-apple-darwin15-strip'
+pkgconfig = '/usr/bin/pkg-config'
+
+[properties]
+root = '/usr/universal-apple-darwin/SDK/MacOSX10.11.sdk'
+c_args = ['-arch', 'i386', '-arch', 'x86_64']
+c_link_args = ['-arch', 'i386', '-arch', 'x86_64']
+needs_exe_wrapper = true
diff --git a/meson/x86_64-linux-gnu b/meson/x86_64-linux-gnu
new file mode 100644
index 0000000..b09321c
--- /dev/null
+++ b/meson/x86_64-linux-gnu
@@ -0,0 +1,16 @@
+[host_machine]
+system = 'linux'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[binaries]
+c = '/usr/bin/x86_64-linux-gnu-gcc'
+cpp = '/usr/bin/x86_64-linux-gnu-g++'
+ar = '/usr/bin/x86_64-linux-gnu-ar'
+strip = '/usr/bin/x86_64-linux-gnu-strip'
+pkgconfig = '/usr/bin/pkg-config'
+
+[properties]
+c_link_args = ['-Wl,-z,defs']
+needs_exe_wrapper = false
diff --git a/meson/x86_64-w64-mingw32 b/meson/x86_64-w64-mingw32
new file mode 100644
index 0000000..40c8a32
--- /dev/null
+++ b/meson/x86_64-w64-mingw32
@@ -0,0 +1,17 @@
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[binaries]
+c = '/usr/bin/x86_64-w64-mingw32-gcc'
+cpp = '/usr/bin/x86_64-w64-mingw32-g++'
+ar = '/usr/bin/x86_64-w64-mingw32-ar'
+strip = '/usr/bin/x86_64-w64-mingw32-strip'
+pkgconfig = '/usr/bin/pkg-config'
+exe_wrapper = '/usr/bin/wine64'
+
+[properties]
+root = '/usr/x86_64-w64-mingw32'
+needs_exe_wrapper = true
diff --git a/midi.png b/midi.png
new file mode 100644
index 0000000..57d188c
--- /dev/null
+++ b/midi.png
Binary files differ
diff --git a/nk_pugl/COPYING b/nk_pugl/COPYING
new file mode 100644
index 0000000..ddb9a46
--- /dev/null
+++ b/nk_pugl/COPYING
@@ -0,0 +1,201 @@
+ The Artistic License 2.0
+
+ Copyright (c) 2000-2006, The Perl Foundation.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+Preamble
+
+This license establishes the terms under which a given free software
+Package may be copied, modified, distributed, and/or redistributed.
+The intent is that the Copyright Holder maintains some artistic
+control over the development of that Package while still keeping the
+Package available as open source and free software.
+
+You are always permitted to make arrangements wholly outside of this
+license directly with the Copyright Holder of a given Package. If the
+terms of this license do not permit the full use that you propose to
+make of the Package, you should contact the Copyright Holder and seek
+a different licensing arrangement.
+
+Definitions
+
+ "Copyright Holder" means the individual(s) or organization(s)
+ named in the copyright notice for the entire Package.
+
+ "Contributor" means any party that has contributed code or other
+ material to the Package, in accordance with the Copyright Holder's
+ procedures.
+
+ "You" and "your" means any person who would like to copy,
+ distribute, or modify the Package.
+
+ "Package" means the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection and/or of
+ those files. A given Package may consist of either the Standard
+ Version, or a Modified Version.
+
+ "Distribute" means providing a copy of the Package or making it
+ accessible to anyone else, or in the case of a company or
+ organization, to others outside of your company or organization.
+
+ "Distributor Fee" means any fee that you charge for Distributing
+ this Package or providing support for this Package to another
+ party. It does not mean licensing fees.
+
+ "Standard Version" refers to the Package if it has not been
+ modified, or has been modified only in ways explicitly requested
+ by the Copyright Holder.
+
+ "Modified Version" means the Package, if it has been changed, and
+ such changes were not explicitly requested by the Copyright
+ Holder.
+
+ "Original License" means this Artistic License as Distributed with
+ the Standard Version of the Package, in its current version or as
+ it may be modified by The Perl Foundation in the future.
+
+ "Source" form means the source code, documentation source, and
+ configuration files for the Package.
+
+ "Compiled" form means the compiled bytecode, object code, binary,
+ or any other form resulting from mechanical transformation or
+ translation of the Source form.
+
+
+Permission for Use and Modification Without Distribution
+
+(1) You are permitted to use the Standard Version and create and use
+Modified Versions for any purpose without restriction, provided that
+you do not Distribute the Modified Version.
+
+
+Permissions for Redistribution of the Standard Version
+
+(2) You may Distribute verbatim copies of the Source form of the
+Standard Version of this Package in any medium without restriction,
+either gratis or for a Distributor Fee, provided that you duplicate
+all of the original copyright notices and associated disclaimers. At
+your discretion, such verbatim copies may or may not include a
+Compiled form of the Package.
+
+(3) You may apply any bug fixes, portability changes, and other
+modifications made available from the Copyright Holder. The resulting
+Package will still be considered the Standard Version, and as such
+will be subject to the Original License.
+
+
+Distribution of Modified Versions of the Package as Source
+
+(4) You may Distribute your Modified Version as Source (either gratis
+or for a Distributor Fee, and with or without a Compiled form of the
+Modified Version) provided that you clearly document how it differs
+from the Standard Version, including, but not limited to, documenting
+any non-standard features, executables, or modules, and provided that
+you do at least ONE of the following:
+
+ (a) make the Modified Version available to the Copyright Holder
+ of the Standard Version, under the Original License, so that the
+ Copyright Holder may include your modifications in the Standard
+ Version.
+
+ (b) ensure that installation of your Modified Version does not
+ prevent the user installing or running the Standard Version. In
+ addition, the Modified Version must bear a name that is different
+ from the name of the Standard Version.
+
+ (c) allow anyone who receives a copy of the Modified Version to
+ make the Source form of the Modified Version available to others
+ under
+
+ (i) the Original License or
+
+ (ii) a license that permits the licensee to freely copy,
+ modify and redistribute the Modified Version using the same
+ licensing terms that apply to the copy that the licensee
+ received, and requires that the Source form of the Modified
+ Version, and of any works derived from it, be made freely
+ available in that license fees are prohibited but Distributor
+ Fees are allowed.
+
+
+Distribution of Compiled Forms of the Standard Version
+or Modified Versions without the Source
+
+(5) You may Distribute Compiled forms of the Standard Version without
+the Source, provided that you include complete instructions on how to
+get the Source of the Standard Version. Such instructions must be
+valid at the time of your distribution. If these instructions, at any
+time while you are carrying out such distribution, become invalid, you
+must provide new instructions on demand or cease further distribution.
+If you provide valid instructions or cease distribution within thirty
+days after you become aware that the instructions are invalid, then
+you do not forfeit any of your rights under this license.
+
+(6) You may Distribute a Modified Version in Compiled form without
+the Source, provided that you comply with Section 4 with respect to
+the Source of the Modified Version.
+
+
+Aggregating or Linking the Package
+
+(7) You may aggregate the Package (either the Standard Version or
+Modified Version) with other packages and Distribute the resulting
+aggregation provided that you do not charge a licensing fee for the
+Package. Distributor Fees are permitted, and licensing fees for other
+components in the aggregation are permitted. The terms of this license
+apply to the use and Distribution of the Standard or Modified Versions
+as included in the aggregation.
+
+(8) You are permitted to link Modified and Standard Versions with
+other works, to embed the Package in a larger work of your own, or to
+build stand-alone binary or bytecode versions of applications that
+include the Package, and Distribute the result without restriction,
+provided the result does not expose a direct interface to the Package.
+
+
+Items That are Not Considered Part of a Modified Version
+
+(9) Works (including, but not limited to, modules and scripts) that
+merely extend or make use of the Package, do not, by themselves, cause
+the Package to be a Modified Version. In addition, such works are not
+considered parts of the Package itself, and are not subject to the
+terms of this license.
+
+
+General Provisions
+
+(10) Any use, modification, and distribution of the Standard or
+Modified Versions is governed by this Artistic License. By using,
+modifying or distributing the Package, you accept this license. Do not
+use, modify, or distribute the Package, if you do not accept this
+license.
+
+(11) If your Modified Version has been derived from a Modified
+Version made by someone other than you, you are nevertheless required
+to ensure that your Modified Version complies with the requirements of
+this license.
+
+(12) This license does not grant you the right to use any trademark,
+service mark, tradename, or logo of the Copyright Holder.
+
+(13) This license includes the non-exclusive, worldwide,
+free-of-charge patent license to make, have made, use, offer to sell,
+sell, import and otherwise transfer the Package with respect to any
+patent claims licensable by the Copyright Holder that are necessarily
+infringed by the Package. If you institute patent litigation
+(including a cross-claim or counterclaim) against any party alleging
+that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the
+date that such litigation is filed.
+
+(14) Disclaimer of Warranty:
+THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
+LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/nk_pugl.h b/nk_pugl/nk_pugl.h
index a84d7e8..a84d7e8 100644
--- a/nk_pugl.h
+++ b/nk_pugl/nk_pugl.h
diff --git a/nuk.c b/nuk.c
new file mode 100644
index 0000000..4b8d7e0
--- /dev/null
+++ b/nuk.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <nuk.h>
+
+#define CONTROL_N 16
+
+typedef struct _plughandle_t plughandle_t;
+
+struct _plughandle_t {
+ LV2_URID_Map *map;
+ LV2_Atom_Forge forge;
+
+ LV2_Log_Log *log;
+ LV2_Log_Logger logger;
+
+ const LV2_Atom_Sequence *control;
+ LV2_Atom_Sequence *notify;
+
+ int32_t *toggle [CONTROL_N];
+ float *cntrl [CONTROL_N];
+ int32_t *radio;
+};
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor, double rate,
+ const char *bundle_path, const LV2_Feature *const *features)
+{
+ plughandle_t *handle = calloc(1, sizeof(plughandle_t));
+ if(!handle)
+ return NULL;
+
+ for(unsigned i=0; features[i]; i++)
+ {
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->map = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_LOG__log))
+ handle->log = features[i]->data;
+ }
+
+ if(!handle->map)
+ {
+ fprintf(stderr,
+ "%s: Host does not support urid:map\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+
+ if(handle->log)
+ lv2_log_logger_init(&handle->logger, handle->map, handle->log);
+
+ lv2_atom_forge_init(&handle->forge, handle->map);
+
+ return handle;
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void *data)
+{
+ plughandle_t *handle = instance;
+
+ switch(port)
+ {
+ case 0:
+ handle->control = data;
+ break;
+ case 1:
+ handle->notify = data;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ handle->toggle[port - 2] = data;
+ break;
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ handle->cntrl[port - CONTROL_N - 2] = data;
+ break;
+ case 34:
+ handle->radio = data;
+ break;
+ }
+}
+
+static void
+run(LV2_Handle instance, uint32_t nsamples)
+{
+ plughandle_t *handle = instance;
+
+ const uint32_t sz = lv2_atom_total_size(&handle->control->atom);
+ memcpy(handle->notify, handle->control, sz);
+}
+
+static void
+cleanup(LV2_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ free(handle);
+}
+
+static const LV2_Descriptor nuk_nuk = {
+ .URI = NUK_PREFIX"nuk",
+ .instantiate = instantiate,
+ .connect_port = connect_port,
+ .activate = NULL,
+ .run = run,
+ .deactivate = NULL,
+ .cleanup = cleanup,
+ .extension_data = NULL
+};
+
+LV2_SYMBOL_EXPORT const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
+{
+ switch(index)
+ {
+ case 0:
+ return &nuk_nuk;
+ default:
+ return NULL;
+ }
+}
diff --git a/nuk.h b/nuk.h
new file mode 100644
index 0000000..f2c31d5
--- /dev/null
+++ b/nuk.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#ifndef _NUK_LV2_H
+#define _NUK_LV2_H
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
+#include "lv2/lv2plug.in/ns/ext/log/log.h"
+#include "lv2/lv2plug.in/ns/ext/log/logger.h"
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
+#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+
+#define NUK_URI "http://open-music-kontrollers.ch/lv2/nuk"
+#define NUK_PREFIX NUK_URI"#"
+
+#endif // _NUK_LV2_H
diff --git a/nuk.ttl b/nuk.ttl
new file mode 100644
index 0000000..662b3bd
--- /dev/null
+++ b/nuk.ttl
@@ -0,0 +1,372 @@
+# Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+#
+# This is free software: you can redistribute it and/or modify
+# it under the terms of the Artistic License 2.0 as published by
+# The Perl Foundation.
+#
+# This source is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Artistic License 2.0 for more details.
+#
+# You should have received a copy of the Artistic License 2.0
+# along the source as a COPYING file. If not, obtain it from
+# http://www.perlfoundation.org/artistic_license_2_0.
+
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
+@prefix log: <http://lv2plug.in/ns/ext/log#> .
+@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
+
+@prefix lic: <http://opensource.org/licenses/> .
+@prefix omk: <http://open-music-kontrollers.ch/ventosus#> .
+@prefix proj: <http://open-music-kontrollers.ch/lv2/> .
+@prefix nuk: <http://open-music-kontrollers.ch/lv2/nuk#> .
+
+# Maintainer
+omk:me
+ a foaf:Person ;
+ foaf:name "Hanspeter Portner" ;
+ foaf:mbox <mailto:dev@open-music-kontrollers.ch> ;
+ foaf:homepage <http://open-music-kontrollers.ch> .
+
+# Project
+proj:nuk
+ a doap:Project ;
+ doap:maintainer omk:me ;
+ doap:name "Nuk Bundle" .
+
+# Plugin
+nuk:nuk
+ a lv2:Plugin,
+ lv2:AnalyserPlugin ;
+ doap:name "Nuk" ;
+ doap:license lic:Artistic-2.0 ;
+ lv2:project proj:nuk ;
+ lv2:requiredFeature urid:map ;
+ lv2:optionalFeature lv2:isLive, lv2:hardRTCapable, log:log ;
+
+ lv2:port [
+ a lv2:InputPort ,
+ atom:AtomPort ;
+ atom:bufferType atom:Sequence ;
+ atom:supports midi:MidiEvent ;
+ lv2:index 0 ;
+ lv2:symbol "control" ;
+ lv2:name "Control" ;
+ lv2:designation lv2:control ;
+ ] , [
+ a lv2:OutputPort ,
+ atom:AtomPort ;
+ atom:bufferType atom:Sequence ;
+ atom:supports midi:MidiEvent ;
+ lv2:index 1 ;
+ lv2:symbol "notify" ;
+ lv2:name "Notify" ;
+ lv2:default 0 ;
+ lv2:designation lv2:control ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 2 ;
+ lv2:symbol "toggled_1" ;
+ lv2:name "Toggle 1" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 3 ;
+ lv2:symbol "toggled_2" ;
+ lv2:name "Toggle 2" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 4 ;
+ lv2:symbol "toggled_3" ;
+ lv2:name "Toggle 3" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 5 ;
+ lv2:symbol "toggled_4" ;
+ lv2:name "Toggle 4" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 6 ;
+ lv2:symbol "toggled_5" ;
+ lv2:name "Toggle 5" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 7 ;
+ lv2:symbol "toggled_6" ;
+ lv2:name "Toggle 6" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 8 ;
+ lv2:symbol "toggled_7" ;
+ lv2:name "Toggle 7" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 9 ;
+ lv2:symbol "toggled_8" ;
+ lv2:name "Toggle 8" ;
+ lv2:default 0 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 10 ;
+ lv2:symbol "toggled_9" ;
+ lv2:name "Toggle 9" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 11 ;
+ lv2:symbol "toggled_10" ;
+ lv2:name "Toggle 10" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 12 ;
+ lv2:symbol "toggled_11" ;
+ lv2:name "Toggle 11" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 13 ;
+ lv2:symbol "toggled_12" ;
+ lv2:name "Toggle 12" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 14 ;
+ lv2:symbol "toggled_13" ;
+ lv2:name "Toggle 13" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 15 ;
+ lv2:symbol "toggled_14" ;
+ lv2:name "Toggle 14" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 16 ;
+ lv2:symbol "toggled_15" ;
+ lv2:name "Toggle 15" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 17 ;
+ lv2:symbol "toggled_16" ;
+ lv2:name "Toggle 16" ;
+ lv2:default 1 ;
+ lv2:portProperty lv2:toggled ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 18 ;
+ lv2:symbol "control_1" ;
+ lv2:name "Control 1" ;
+ lv2:default 0.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 19 ;
+ lv2:symbol "control_2" ;
+ lv2:name "Control 2" ;
+ lv2:default 25.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 20 ;
+ lv2:symbol "control_3" ;
+ lv2:name "Control 3" ;
+ lv2:default 36.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 21 ;
+ lv2:symbol "control_4" ;
+ lv2:name "Control 4" ;
+ lv2:default 44.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 22 ;
+ lv2:symbol "control_5" ;
+ lv2:name "Control 5" ;
+ lv2:default 51.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 23 ;
+ lv2:symbol "control_6" ;
+ lv2:name "Control 6" ;
+ lv2:default 57.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 24 ;
+ lv2:symbol "control_7" ;
+ lv2:name "Control 7" ;
+ lv2:default 63.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 25 ;
+ lv2:symbol "control_8" ;
+ lv2:name "Control 8" ;
+ lv2:default 68.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 26 ;
+ lv2:symbol "control_9" ;
+ lv2:name "Control 9" ;
+ lv2:default 73.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 27 ;
+ lv2:symbol "control_10" ;
+ lv2:name "Control 10" ;
+ lv2:default 77.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 28 ;
+ lv2:symbol "control_11" ;
+ lv2:name "Control 11" ;
+ lv2:default 81.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 29 ;
+ lv2:symbol "control_12" ;
+ lv2:name "Control 12" ;
+ lv2:default 85.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 30 ;
+ lv2:symbol "control_13" ;
+ lv2:name "Control 13" ;
+ lv2:default 89.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 31 ;
+ lv2:symbol "control_14" ;
+ lv2:name "Control 14" ;
+ lv2:default 93.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 32 ;
+ lv2:symbol "control_15" ;
+ lv2:name "Control 15" ;
+ lv2:default 96.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 33 ;
+ lv2:symbol "control_16" ;
+ lv2:name "Control 16" ;
+ lv2:default 100.0 ;
+ lv2:minimum 0.0 ;
+ lv2:maximum 100.0 ;
+ ] , [
+ a lv2:InputPort ,
+ lv2:ControlPort ;
+ lv2:index 34 ;
+ lv2:symbol "radio" ;
+ lv2:name "Radio" ;
+ lv2:default 0 ;
+ lv2:minimum 0 ;
+ lv2:maximum 16 ;
+ lv2:portProperty lv2:integer, lv2:enumeration ;
+ lv2:scalePoint
+ [ rdfs:label "*1*" ; rdf:value 0 ] ,
+ [ rdfs:label "*2*" ; rdf:value 1 ] ,
+ [ rdfs:label "*3*" ; rdf:value 2 ] ,
+ [ rdfs:label "*4*" ; rdf:value 3 ] ,
+ [ rdfs:label "*5*" ; rdf:value 4 ] ,
+ [ rdfs:label "*6*" ; rdf:value 5 ] ,
+ [ rdfs:label "*7*" ; rdf:value 6 ] ,
+ [ rdfs:label "*8*" ; rdf:value 7 ] ,
+ [ rdfs:label "*9*" ; rdf:value 8 ] ,
+ [ rdfs:label "*10*" ; rdf:value 9 ] ,
+ [ rdfs:label "*11*" ; rdf:value 10 ] ,
+ [ rdfs:label "*12*" ; rdf:value 11 ] ,
+ [ rdfs:label "*13*" ; rdf:value 12 ] ,
+ [ rdfs:label "*14*" ; rdf:value 13 ] ,
+ [ rdfs:label "*15*" ; rdf:value 14 ] ,
+ [ rdfs:label "*16*" ; rdf:value 15 ] ;
+ ] .
diff --git a/nuk_ui.c b/nuk_ui.c
new file mode 100644
index 0000000..c04c93b
--- /dev/null
+++ b/nuk_ui.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the Artistic License 2.0 as published by
+ * The Perl Foundation.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Artistic License 2.0 for more details.
+ *
+ * You should have received a copy of the Artistic License 2.0
+ * along the source as a COPYING file. If not, obtain it from
+ * http://www.perlfoundation.org/artistic_license_2_0.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <nuk.h>
+
+#define NK_PUGL_IMPLEMENTATION
+#include "nk_pugl/nk_pugl.h"
+
+//#define SHOW_OVERVIEW
+#ifdef SHOW_OVERVIEW
+# 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 "nuklear/demo/overview.c"
+#endif
+
+#define CONTROL_N 16
+
+typedef struct _plughandle_t plughandle_t;
+
+struct _plughandle_t {
+ LV2_URID_Map *map;
+ LV2_Atom_Forge forge;
+
+ LV2_Log_Log *log;
+ LV2_Log_Logger logger;
+
+ nk_pugl_window_t win;
+ struct {
+ struct nk_image audio;
+ struct nk_image midi;
+ } icon;
+
+ LV2UI_Controller *controller;
+ LV2UI_Write_Function writer;
+
+ int toggle [CONTROL_N];
+ float cntrl [CONTROL_N];
+ unsigned radio;
+};
+
+static const char *combo_labels [2] = {
+ "off",
+ "on"
+};
+
+static inline void
+_write_int(plughandle_t *handle, uint32_t port, int i)
+{
+ const float f = i;
+ handle->writer(handle->controller, port, sizeof(float), 0, &f);
+}
+
+static inline void
+_write_flt(plughandle_t *handle, uint32_t port, float f)
+{
+ handle->writer(handle->controller, port, sizeof(float), 0, &f);
+}
+
+static float
+_dial_numeric_behavior(struct nk_context *ctx, struct nk_rect bounds,
+ enum nk_widget_states *states, int *divider, struct nk_input *in)
+{
+ const struct nk_mouse_button *btn = &in->mouse.buttons[NK_BUTTON_LEFT];;
+ const bool left_mouse_down = btn->down;
+ const bool left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,
+ NK_BUTTON_LEFT, bounds, nk_true);
+
+ float dd = 0.f;
+ if(left_mouse_down && left_mouse_click_in_cursor)
+ {
+ const float dx = in->mouse.delta.x;
+ const float dy = in->mouse.delta.y;
+ dd = fabs(dx) > fabs(dy) ? dx : -dy;
+
+ *states = NK_WIDGET_STATE_ACTIVED;
+ }
+ else if(nk_input_is_mouse_hovering_rect(in, bounds))
+ {
+ if(in->mouse.scroll_delta.y != 0.f) // has scrolling
+ {
+ dd = in->mouse.scroll_delta.y;
+ in->mouse.scroll_delta.y = 0.f;
+ }
+
+ *states = NK_WIDGET_STATE_HOVER;
+ }
+
+ if(nk_input_is_key_down(in, NK_KEY_CTRL))
+ *divider *= 4;
+ if(nk_input_is_key_down(in, NK_KEY_SHIFT))
+ *divider *= 4;
+
+ return dd;
+}
+
+static void
+_dial_numeric_draw(struct nk_context *ctx, struct nk_rect bounds,
+ enum nk_widget_states states, float perc, struct nk_color color)
+{
+ struct nk_command_buffer *canv= nk_window_get_canvas(ctx);
+ const struct nk_style_item *bg = NULL;
+ const struct nk_style_item *fg = NULL;
+
+ switch(states)
+ {
+ case NK_WIDGET_STATE_HOVER:
+ {
+ bg = &ctx->style.progress.hover;
+ fg = &ctx->style.progress.cursor_hover;
+ } break;
+ case NK_WIDGET_STATE_ACTIVED:
+ {
+ bg = &ctx->style.progress.active;
+ fg = &ctx->style.progress.cursor_active;
+ } break;
+ default:
+ {
+ bg = &ctx->style.progress.normal;
+ fg = &ctx->style.progress.cursor_normal;
+ } break;
+ }
+
+ const struct nk_color bg_color = bg->data.color;
+ struct nk_color fg_color = fg->data.color;
+
+ fg_color.r = (int)fg_color.r * color.r / 0xff;
+ fg_color.g = (int)fg_color.g * color.g / 0xff;
+ fg_color.b = (int)fg_color.b * color.b / 0xff;
+ fg_color.a = (int)fg_color.a * color.a / 0xff;
+
+ const float w2 = bounds.w/2;
+ const float h2 = bounds.h/2;
+ const float r1 = NK_MIN(w2, h2);
+ const float r2 = r1 / 2;
+ const float cx = bounds.x + w2;
+ const float cy = bounds.y + h2;
+ const float aa = M_PI/6;
+ const float a1 = M_PI/2 + aa;
+ const float a2 = 2*M_PI + M_PI/2 - aa;
+ const float a3 = a1 + (a2 - a1)*perc;
+
+ nk_stroke_arc(canv, cx, cy, (r1+r2)/2, a1, a2, r1-r2, bg_color);
+ nk_stroke_arc(canv, cx, cy, (r1+r2)/2, a1, a3, r1-r2, fg_color);
+}
+
+static int
+_dial_double(struct nk_context *ctx, double min, double *val, double max, float mul,
+ struct nk_color color, bool editable)
+{
+ const double tmp = *val;
+ struct nk_rect bounds = nk_layout_space_bounds(ctx);
+ const enum nk_widget_layout_states layout_states = nk_widget(&bounds, ctx);
+
+ if(layout_states != NK_WIDGET_INVALID)
+ {
+ enum nk_widget_states states = NK_WIDGET_STATE_INACTIVE;
+ const double range = max - min;
+ struct nk_input *in = (ctx->current->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
+
+ if(in && editable)
+ {
+ int divider = 1;
+ const float dd = _dial_numeric_behavior(ctx, bounds, &states, &divider, in);
+
+ if(dd != 0.f) // update value
+ {
+ const double per_pixel_inc = mul * range / bounds.w / divider;
+
+ *val += dd * per_pixel_inc;
+ *val = NK_CLAMP(min, *val, max);
+ }
+ }
+
+ const float perc = (*val - min) / range;
+ _dial_numeric_draw(ctx, bounds, states, perc, color);
+ }
+
+ return tmp != *val;
+}
+
+static int
+_dial_float(struct nk_context *ctx, float min, float *val, float max, float mul)
+{
+ double tmp = *val;
+ const int res = _dial_double(ctx, min, &tmp, max, mul, nk_white, true);
+ *val = tmp;
+
+ return res;
+}
+
+static void
+_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
+{
+ plughandle_t *handle = data;
+
+#ifdef SHOW_OVERVIEW
+ overview(ctx);
+#else
+ const float widget_h = 20 * nk_pugl_get_scale(&handle->win);
+ const float width2 = wbounds.w/2;
+ const float height2 = wbounds.h/2;
+
+ const char *window_name = "Nuk";
+ if(nk_begin(ctx, window_name, wbounds, NK_WINDOW_CLOSABLE | NK_WINDOW_NO_SCROLLBAR))
+ {
+ const struct nk_panel *root = nk_window_get_panel(ctx);
+
+ const nk_flags nuk_f = NK_WINDOW_BORDER | NK_WINDOW_TITLE;
+ const float nuk_h = root->bounds.h - root->footer_height;
+ nk_layout_row_dynamic(ctx, nuk_h/2, 1);
+
+ if(nk_group_begin(ctx, "Controls", nuk_f))
+ {
+ const struct nk_panel *panel = nk_window_get_panel(ctx);
+ const nk_flags group_f = NK_WINDOW_BORDER | NK_WINDOW_TITLE;
+ const float group_h = panel->bounds.h - panel->footer_height;
+ nk_layout_row_dynamic(ctx, group_h, 9);
+
+ if(nk_group_begin(ctx, "Buttons", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [12];
+ snprintf(label, 12, "Button %i", i + 1);
+ if(nk_button_symbol_label(ctx,
+ handle->toggle[i] ? NK_SYMBOL_CIRCLE_OUTLINE : NK_SYMBOL_CIRCLE_SOLID,
+ label, NK_TEXT_ALIGN_LEFT))
+ {
+ handle->toggle[i] = !handle->toggle[i];
+ _write_int(handle, i + 2, handle->toggle[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Toggles", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [12];
+ snprintf(label, 12, "Toggle %i", i + 1);
+ if(nk_checkbox_label(ctx, label, &handle->toggle[i]))
+ {
+ _write_int(handle, i + 2, handle->toggle[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Selectables", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [16];
+ snprintf(label, 16, "Selectable %i", i + 1);
+ if(nk_selectable_image_label(ctx,
+ handle->toggle[i] ? handle->icon.midi: handle->icon.audio,
+ label, NK_TEXT_ALIGN_LEFT, &handle->toggle[i]))
+ {
+ _write_int(handle, i + 2, handle->toggle[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Comboboxes", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ const struct nk_panel *panel2 = nk_window_get_panel(ctx);
+ const int tmp = handle->toggle[i];
+ nk_combobox(ctx, combo_labels, 2, &handle->toggle[i], widget_h,
+ nk_vec2(panel2->bounds.w, 3*widget_h));
+ if(tmp != handle->toggle[i])
+ {
+ _write_int(handle, i + 2, handle->toggle[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Radiobuttons", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [12];
+ snprintf(label, 12, "Radio %i", i + 1);
+ if(nk_option_label(ctx, label, handle->radio == i))
+ {
+ handle->radio = i;
+ _write_int(handle, 2 + 2*CONTROL_N, handle->radio);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Properties", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [12];
+ snprintf(label, 12, "No. %i", i + 1);
+ const float tmp = handle->cntrl[i];
+ nk_property_float(ctx, label, 0.f, &handle->cntrl[i], 100.f, 1.f, 1.f);
+ if(tmp != handle->cntrl[i])
+ {
+ _write_flt(handle, i + 2 + CONTROL_N, handle->cntrl[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Sliders", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ if(nk_slider_float(ctx, 0.f, &handle->cntrl[i], 100.f, 1.f))
+ {
+ _write_flt(handle, i + 2 + CONTROL_N, handle->cntrl[i]);
+ }
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Progressbars", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ nk_prog(ctx, handle->cntrl[i], 100, 0);
+ }
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Values", group_f))
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 1);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ {
+ char label [12];
+ snprintf(label, 12, "Value %i", i + 1);
+ nk_value_float(ctx, label, handle->cntrl[i]);
+ }
+ nk_group_end(ctx);
+ }
+ nk_group_end(ctx);
+ }
+
+ nk_layout_row_dynamic(ctx, nuk_h/2, 3);
+
+ if(nk_group_begin(ctx, "Graphs", nuk_f))
+ {
+ const struct nk_panel *panel = nk_window_get_panel(ctx);
+ const nk_flags group_f = NK_WINDOW_BORDER | NK_WINDOW_TITLE;
+ const float group_h = panel->bounds.h - panel->footer_height;
+ nk_layout_row_dynamic(ctx, group_h, 2);
+
+ // barplot
+ nk_chart_begin(ctx, NK_CHART_COLUMN, CONTROL_N, 0.f, 100.f);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ nk_chart_push(ctx, handle->cntrl[i]);
+ nk_chart_end(ctx);
+
+ // lineplot
+ nk_chart_begin(ctx, NK_CHART_LINES, CONTROL_N, 0.f, 100.f);
+ for(unsigned i=0; i<CONTROL_N; i++)
+ nk_chart_push(ctx, handle->cntrl[i]);
+ nk_chart_end(ctx);
+
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Canvas", nuk_f))
+ {
+ const struct nk_panel *panel = nk_window_get_panel(ctx);
+ const nk_flags group_f = NK_WINDOW_BORDER | NK_WINDOW_TITLE;
+ const float group_h = panel->bounds.h - panel->footer_height;
+ nk_layout_row_dynamic(ctx, group_h, 1);
+
+ const struct nk_vec2 group_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);
+ struct nk_rect bounds = panel->bounds;
+ bounds.x += group_padding.x;
+ bounds.y += group_padding.y;
+ bounds.w -= 2*group_padding.x;
+ bounds.h -= 2*group_padding.y;
+
+ struct nk_command_buffer *canv= nk_window_get_canvas(ctx);
+ nk_widget(&bounds, ctx);
+ {
+ const unsigned r = 10;
+ const unsigned d = r*2;
+ const float dx = (bounds.w - d) / 15.f;
+ const float dy = (bounds.h - d) / 15.f;
+
+ for(unsigned i=0; i<16; i++)
+ {
+ const unsigned x0 = bounds.x + i*dx;
+ const unsigned y0 = bounds.y + i*dy;
+ const unsigned cx = x0 + r;
+ const unsigned cy = y0 + r;
+
+ if(i == handle->radio)
+ {
+ nk_stroke_curve(canv,
+ bounds.x, bounds.y + bounds.h,
+ cx, cy,
+ cx, cy,
+ bounds.x + bounds.w, bounds.y,
+ 2.f, nk_red);
+ }
+
+ nk_fill_circle(canv, nk_rect(x0, y0, d, d),
+ i == handle->radio ? nk_white : nk_black);
+ }
+
+ nk_stroke_rect(canv, bounds, 0.f, 1.0, nk_white);
+ }
+
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Dials", nuk_f))
+ {
+ const struct nk_panel *panel = nk_window_get_panel(ctx);
+ const nk_flags group_f = NK_WINDOW_BORDER | NK_WINDOW_TITLE;
+ const float group_h = panel->bounds.h - panel->footer_height;
+
+ for(unsigned j=0; j<CONTROL_N; j+=4)
+ {
+ nk_layout_row_dynamic(ctx, nk_layout_space_bounds(ctx).w/8, 4);
+ for(unsigned k=0; k<4; k++)
+ {
+ const unsigned i = j + k;
+
+ if(_dial_float(ctx, 0.f, &handle->cntrl[i], 100.f, 1.f))
+ {
+ _write_flt(handle, i + 2 + CONTROL_N, handle->cntrl[i]);
+ }
+ }
+
+ nk_layout_row_dynamic(ctx, widget_h, 4);
+ for(unsigned k=0; k<4; k++)
+ {
+ const unsigned i = j + k;
+
+ char label [12];
+ snprintf(label, 12, "%02i:", i + 1);
+ const float tmp = handle->cntrl[i];
+
+ nk_property_float(ctx, label, 0.f, &handle->cntrl[i], 100.f, 1.f, 1.f);
+ if(tmp != handle->cntrl[i])
+ {
+ _write_flt(handle, i + 2 + CONTROL_N, handle->cntrl[i]);
+ }
+ }
+ }
+
+ nk_group_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ if(nk_window_is_closed(ctx, "Nuk"))
+ {
+ nk_pugl_quit(&handle->win);
+ }
+#endif
+}
+
+static LV2UI_Handle
+instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
+ const char *bundle_path, LV2UI_Write_Function write_function,
+ LV2UI_Controller controller, LV2UI_Widget *widget,
+ const LV2_Feature *const *features)
+{
+ plughandle_t *handle = calloc(1, sizeof(plughandle_t));
+ if(!handle)
+ return NULL;
+
+ void *parent = NULL;
+ LV2UI_Resize *host_resize = NULL;
+ for(int i=0; features[i]; i++)
+ {
+ if(!strcmp(features[i]->URI, LV2_UI__parent))
+ parent = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_UI__resize))
+ host_resize = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->map = features[i]->data;
+ else if(!strcmp(features[i]->URI, LV2_LOG__log))
+ handle->log = features[i]->data;
+ }
+
+ if(!parent)
+ {
+ fprintf(stderr,
+ "%s: Host does not support ui:parent\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+ if(!handle->map)
+ {
+ fprintf(stderr,
+ "%s: Host does not support urid:map\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+
+ if(handle->log)
+ lv2_log_logger_init(&handle->logger, handle->map, handle->log);
+
+ lv2_atom_forge_init(&handle->forge, handle->map);
+
+ handle->controller = controller;
+ handle->writer = write_function;
+
+ nk_pugl_config_t *cfg = &handle->win.cfg;
+#ifdef SHOW_OVERVIEW
+ cfg->width = 800;
+ cfg->height = 800;
+#else
+ cfg->width = 1440;
+ cfg->height = 720;
+#endif
+ cfg->resizable = true;
+ cfg->ignore = false;
+ cfg->class = "nuklear";
+ cfg->title = "Nuklear";
+ cfg->parent = (intptr_t)parent;
+ cfg->host_resize = host_resize;
+ cfg->data = handle;
+ cfg->expose = _expose;
+
+ if(asprintf(&cfg->font.face, "%sAbel-Regular.ttf", bundle_path) == -1)
+ cfg->font.face = NULL;
+ cfg->font.size = 16;
+
+ *(intptr_t *)widget = nk_pugl_init(&handle->win);
+ nk_pugl_show(&handle->win);
+
+ char *path;
+ if(asprintf(&path, "%saudio.png", bundle_path) != -1)
+ {
+ handle->icon.audio = nk_pugl_icon_load(&handle->win, path);
+ free(path);
+ }
+
+ if(asprintf(&path, "%smidi.png", bundle_path) != -1)
+ {
+ handle->icon.midi = nk_pugl_icon_load(&handle->win, path);
+ free(path);
+ }
+
+ return handle;
+}
+
+static void
+cleanup(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ if(handle->win.cfg.font.face)
+ free(handle->win.cfg.font.face);
+ nk_pugl_icon_unload(&handle->win, handle->icon.audio);
+ nk_pugl_icon_unload(&handle->win, handle->icon.midi);
+ nk_pugl_hide(&handle->win);
+ nk_pugl_shutdown(&handle->win);
+
+ free(handle);
+}
+
+static void
+port_event(LV2UI_Handle instance, uint32_t index, uint32_t size,
+ uint32_t protocol, const void *buf)
+{
+ plughandle_t *handle = instance;
+
+ if( (size == sizeof(float)) && (protocol == 0) )
+ {
+ const float *flt = buf;
+
+ switch(index)
+ {
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ {
+ const unsigned idx = index - 2;
+ const int32_t val = *flt != 0.f ? 1 : 0;
+ if(val != handle->toggle[idx])
+ {
+ handle->toggle[idx] =val;
+ nk_pugl_post_redisplay(&handle->win);
+ }
+ break;
+ }
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ {
+ const unsigned idx = index - CONTROL_N - 2;
+ const float val = *flt;
+ if(val != handle->cntrl[idx])
+ {
+ handle->cntrl[idx] = val;
+ nk_pugl_post_redisplay(&handle->win);
+ }
+ break;
+ }
+ case 34:
+ {
+ const unsigned val = floor(*flt);
+ if(val != handle->radio)
+ {
+ handle->radio = val;
+ nk_pugl_post_redisplay(&handle->win);
+ }
+ break;
+ }
+ }
+ }
+}
+
+static int
+_idle(LV2UI_Handle instance)
+{
+ plughandle_t *handle = instance;
+
+ return nk_pugl_process_events(&handle->win);
+}
+
+static const LV2UI_Idle_Interface idle_ext = {
+ .idle = _idle
+};
+
+static int
+_resize(LV2UI_Handle instance, int width, int height)
+{
+ plughandle_t *handle = instance;
+
+ return nk_pugl_resize(&handle->win, width, height);
+}
+
+static const LV2UI_Resize resize_ext = {
+ .ui_resize = _resize
+};
+
+static const void *
+extension_data(const char *uri)
+{
+ if(!strcmp(uri, LV2_UI__idleInterface))
+ return &idle_ext;
+ else if(!strcmp(uri, LV2_UI__resize))
+ return &resize_ext;
+
+ return NULL;
+}
+
+static const LV2UI_Descriptor nuk_nuk_ui = {
+ .URI = NUK_PREFIX"nuk_ui",
+ .instantiate = instantiate,
+ .cleanup = cleanup,
+ .port_event = port_event,
+ .extension_data = extension_data
+};
+
+LV2_SYMBOL_EXPORT const LV2UI_Descriptor*
+lv2ui_descriptor(uint32_t index)
+{
+ switch(index)
+ {
+ case 0:
+ return &nuk_nuk_ui;
+ default:
+ return NULL;
+ }
+}
diff --git a/nuk_ui.ttl b/nuk_ui.ttl
new file mode 100644
index 0000000..3ec8b6c
--- /dev/null
+++ b/nuk_ui.ttl
@@ -0,0 +1,32 @@
+# Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
+#
+# This is free software: you can redistribute it and/or modify
+# it under the terms of the Artistic License 2.0 as published by
+# The Perl Foundation.
+#
+# This source is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Artistic License 2.0 for more details.
+#
+# You should have received a copy of the Artistic License 2.0
+# along the source as a COPYING file. If not, obtain it from
+# http://www.perlfoundation.org/artistic_license_2_0.
+
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
+@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
+@prefix log: <http://lv2plug.in/ns/ext/log#> .
+
+@prefix nuk: <http://open-music-kontrollers.ch/lv2/nuk#> .
+
+nuk:nuk_ui
+ ui:portNotification [
+ ui:plugin nuk:nuk ;
+ lv2:symbol "notify" ;
+ ui:protocol atom:eventTransfer
+ ] ;
+ lv2:requiredFeature ui:idleInterface, urid:map ;
+ lv2:optionalFeature log:log, ui:resize ;
+ lv2:extensionData ui:idleInterface, ui:resize .
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..6b06b55
--- /dev/null
+++ b/nuklear/.gitignore
@@ -0,0 +1,8 @@
+demo/*/*.exe
+demo/*/*.obj
+demo/*/bin/*
+example/bin/*
+docs/xml
+docs/build
+docs/src
+*.tmp
diff --git a/nuklear/.gitmodules b/nuklear/.gitmodules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nuklear/.gitmodules
diff --git a/nuklear/.travis.yml b/nuklear/.travis.yml
new file mode 100644
index 0000000..80a5ad5
--- /dev/null
+++ b/nuklear/.travis.yml
@@ -0,0 +1,16 @@
+language: c
+
+os:
+ - linux
+
+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
+
+script:
+ - make -C demo/glfw_opengl3 CFLAGS="-Wall -DINCLUDE_ALL"
+ - make -C demo/glfw_opengl2
+ - make -C example
diff --git a/nuklear/Readme.md b/nuklear/Readme.md
new file mode 100644
index 0000000..d097e35
--- /dev/null
+++ b/nuklear/Readme.md
@@ -0,0 +1,165 @@
+# Nuklear
+
+[![Build Status](https://travis-ci.org/vurtun/nuklear.svg)](https://travis-ci.org/vurtun/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 render backend 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 (~18kLOC)
+- Focus on portability, efficiency and simplicity
+- No dependencies (not even the standard library if not wanted)
+- Fully skinnable and customizable
+- Low memory footprint with total memory control if needed or wanted
+- UTF-8 support
+- No global or hidden state
+- Customizable library modules (you can compile and use only what you need)
+- Optional font baker and vertex buffer output
+- [Documentation](https://rawgit.com/vurtun/nuklear/master/doc/nuklear.html)
+
+## 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};
+static int op = EASY;
+static float value = 0.6f;
+static 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
+There are a number of nuklear bindings for different languges created by other authors.
+I cannot atest for their quality since I am not necessarily proficient in either of these
+languages. Furthermore there are no guarantee that all bindings will always be kept up to date:
+
+- [Java](https://github.com/glegris/nuklear4j) by Guillaume Legris
+- [Golang](https://github.com/golang-ui/nuklear) by golang-ui@github.com
+- [Rust](https://github.com/snuk182/nuklear-rust) by snuk182@github.com
+- [Chicken](https://github.com/wasamasa/nuklear) by wasamasa@github.com
+- [Nim](https://github.com/zacharycarter/nuklear-nim) by zacharycarter@github.com
+- [Lua/Löve2d](https://github.com/keharriso/love-nuklear) by Kevin Harrison
+- Python
+ - [pyNuklear](https://github.com/billsix/pyNuklear) by William Emerison Six (ctypes-based wrapper)
+ - [pynk](https://github.com/nathanrw/nuklear-cffi) by nathanrw@github.com (cffi binding)
+- [CSharp/.NET](https://github.com/cartman300/NuklearDotNet) by cartman300@github.com
+
+## Credits
+Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
+
+
+Embeds `stb_texedit`, `stb_truetype` and `stb_rectpack` by Sean Barrett (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
+Barrett 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 available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Micha Mettke
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------
+```
diff --git a/nuklear/demo/allegro5/KeyboardHandleriOS.h b/nuklear/demo/allegro5/KeyboardHandleriOS.h
new file mode 100644
index 0000000..2664d2e
--- /dev/null
+++ b/nuklear/demo/allegro5/KeyboardHandleriOS.h
@@ -0,0 +1,10 @@
+#import <UIKit/UIKit.h>
+
+#include <allegro5/allegro.h>
+
+@interface KeyboardHandleriOS : UIView <UIKeyInput>
+-(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE*)ev_src;
+-(void)show;
+-(void)hide;
+@end
+
diff --git a/nuklear/demo/allegro5/KeyboardHandleriOS.m b/nuklear/demo/allegro5/KeyboardHandleriOS.m
new file mode 100644
index 0000000..206f9e4
--- /dev/null
+++ b/nuklear/demo/allegro5/KeyboardHandleriOS.m
@@ -0,0 +1,120 @@
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#endif
+#import "KeyboardHandleriOS.h"
+#include <allegro5/allegro.h>
+#include <allegro5/allegro_iphone_objc.h>
+@interface KeyboardHandleriOS()
+{
+ ALLEGRO_EVENT_SOURCE *event_source;
+ ALLEGRO_DISPLAY *current_display;
+}
+@end
+@implementation KeyboardHandleriOS
+- (id)init {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
+ self = [self initWithFrame:CGRectMake(-100, -100, 0, 0)];
+ event_source = NULL;
+ current_display = al_get_current_display();
+ UIView* v = al_iphone_get_view(current_display);
+ [v addSubview:self];
+ return self;
+}
+
+- (void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src {
+ event_source = ev_src;
+}
+
+- (UIKeyboardType) keyboardType
+{
+ return UIKeyboardTypeASCIICapable;
+}
+
+- (UITextAutocorrectionType) autocorrectionType
+{
+ return UITextAutocorrectionTypeNo;
+}
+
+-(BOOL)canBecomeFirstResponder {
+ return YES;
+}
+
+- (void)deleteBackward {
+
+ if (!event_source) {
+ NSLog(@"deleteBackward(): No event source found, not sending events");
+ return;
+ }
+
+ ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));
+ ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));
+
+ event_down->type = ALLEGRO_EVENT_KEY_DOWN;
+ event_down->keyboard.display = current_display;
+ event_down->keyboard.keycode = ALLEGRO_KEY_BACKSPACE;
+ event_up->type = ALLEGRO_EVENT_KEY_UP;
+ event_up->keyboard.display = current_display;
+ event_up->keyboard.keycode = ALLEGRO_KEY_BACKSPACE;
+ al_emit_user_event(event_source, event_down, NULL);
+ al_emit_user_event(event_source, event_up, NULL);
+
+ free(event_down);
+ free(event_up);
+}
+
+- (BOOL)hasText {
+ return YES;
+}
+
+- (void)insertText:(NSString *)text
+{
+ if (!event_source) {
+ NSLog(@"insertText(): No event source found, not sending events");
+ return;
+ }
+
+ ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));
+ ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));
+
+ if([text isEqualToString:@"\n"])
+ {
+ event_down->type = ALLEGRO_EVENT_KEY_DOWN;
+ event_down->keyboard.display = current_display;
+ event_down->keyboard.keycode = ALLEGRO_KEY_ENTER;
+ event_up->type = ALLEGRO_EVENT_KEY_UP;
+ event_up->keyboard.display = current_display;
+ event_up->keyboard.keycode = ALLEGRO_KEY_ENTER;
+ al_emit_user_event(event_source, event_down, NULL);
+ al_emit_user_event(event_source, event_up, NULL);
+ [self hide];
+ //m_kb->setDonePressed();
+ }
+ else {
+ event_down->type = ALLEGRO_EVENT_KEY_CHAR;
+ event_down->keyboard.display = current_display;
+ event_down->keyboard.unichar = [text characterAtIndex:0];
+ // doesn't matter what keycode is, nuklear backend ignores it as long as it
+ // isn't a special key
+ event_down->keyboard.keycode = ALLEGRO_KEY_A;
+ al_emit_user_event(event_source, event_down, NULL);
+ }
+ free(event_down);
+ free(event_up);
+}
+
+-(void)show {
+ NSLog(@"Should be showing!");
+ [self performSelectorOnMainThread:@selector(becomeFirstResponder) withObject:nil waitUntilDone:YES];
+}
+-(void)hide {
+ NSLog(@"Should be hiding!");
+ [self performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:YES];
+}
+- (void)keyboardDidHide:(NSNotification *)notification {
+ NSLog(@"keyboardDidHide called");
+}
+
+-(void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
+}
+@end
diff --git a/nuklear/demo/allegro5/Makefile b/nuklear/demo/allegro5/Makefile
new file mode 100644
index 0000000..090a126
--- /dev/null
+++ b/nuklear/demo/allegro5/Makefile
@@ -0,0 +1,22 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS += -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+# TODO: Handle Windows build
+#ifeq ($(OS),Windows_NT)
+#BIN := $(BIN).exe
+#LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+#else
+LIBS = -lallegro -lallegro_main -lallegro_image -lallegro_font \
+ -lallegro_ttf -lallegro_primitives -lm
+#endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/allegro5/Readme.md b/nuklear/demo/allegro5/Readme.md
new file mode 100644
index 0000000..71a4840
--- /dev/null
+++ b/nuklear/demo/allegro5/Readme.md
@@ -0,0 +1,35 @@
+# Allegro v5 nuklear backend
+
+This backend provides support for [Allegro version 5](http://liballeg.org/). It works on on all supported platforms with an OpenGL backend, including iOS and Android.
+
+Touch support is provided by handling the first touch (ignoring any extra simultaneous touches) and emitting nuklear mouse events. nuklear will handle only the first touch like a single left-mouse click. Dragging the touch screen emits mouse-move events.
+
+## Compiling
+You must link with image, font, ttf, and primitives Allegro addons. See the `Makefile`.
+
+## Resolutions
+
+Like every nuklear backend, handling many different resolutions and resolution densities can be tricky. 14px font on a desktop may be perfect, but extremely small on a retina iPad. I recommend writing a middleware that will detect what kind of screen is being used, and modify the sizes of widgets accordingly.
+
+## Soft Keyboard for Touch Screen Devices
+
+Information on how to implement soft keyboard callbacks for Android can be on the Allegro community wiki: https://wiki.allegro.cc/index.php?title=Running_Allegro_applications_on_Android#Displaying_the_Android_keyboard
+
+To display a soft keyboard on iOS, you must create a `UIView` subclass that implements the `UIKeyInput` interface. See `KeyboardHandleriOS.h` and `KeyboardHandleriOS.m` Objective-C source code files for an example on how to do this. As the Allegro keyboard driver does not currently listen for iOS events, we use a custom event emitter to emit keyboard events, which is passed in after initialization with `(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src`. This causes normal keyboard events to be emitted and properly caught by the nuklear backend. The provided `main.c` demo file does not implement this, but with the provided source code files it is not difficult to do. See this Allegro community forum thread for more information: https://www.allegro.cc/forums/thread/616672
+
+To know when nuklear wants to open and close the keyboard, you can check edit widget flags:
+
+```
+nk_flags ed_flags = nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);
+if (ed_flags & NK_EDIT_ACTIVATED)
+ open_ios_soft_keyboard();
+if (ed_flags & NK_EDIT_DEACTIVATED)
+ close_ios_soft_keyboard();
+```
+
+### Manual Soft Keyboard Dismissal
+As the user can dismiss a keyboard manually, nuklear will not be aware when this occurs, and the text edit cursor will think the entry field is still active. I recommend catching the dismiss event, then emitting `ALLEGRO_EVENT_TOUCH_BEGIN` and `ALLEGRO_EVENT_TOUCH_END` events in an unused portion of the screen (like the bottom-right corner). This will simulate the user touching outside of the text entry widget, which will make the edit field inactive.
+
+### The Keyboard Covers Widgets
+
+If you have a widget near the bottom of the screen, the keyboard opening woll cover it, and the user won't see what they are entering. One way to handle this is to make all text edit widgets view-only, and when tapped you dynamically create a new widget above the keyboard that receives all the key strokes. When the user dismisses the keyboard, copy the result from the new widget into the existing read-only text view and destroy the dynamic one. \ No newline at end of file
diff --git a/nuklear/demo/allegro5/main.c b/nuklear/demo/allegro5/main.c
new file mode 100644
index 0000000..624e7c9
--- /dev/null
+++ b/nuklear/demo/allegro5/main.c
@@ -0,0 +1,165 @@
+/* nuklear - 1.32.0 - 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 <allegro5/allegro.h>
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#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_ALLEGRO5_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_allegro5.h"
+
+
+#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 */
+ ALLEGRO_DISPLAY *display = NULL;
+ ALLEGRO_EVENT_QUEUE *event_queue = NULL;
+
+ if (!al_init()) {
+ fprintf(stdout, "failed to initialize allegro5!\n");
+ exit(1);
+ }
+
+ al_install_mouse();
+ al_set_mouse_wheel_precision(150);
+ al_install_keyboard();
+
+ al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_RESIZABLE|ALLEGRO_OPENGL);
+ al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
+ al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
+ display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
+ if (!display) {
+ fprintf(stdout, "failed to create display!\n");
+ exit(1);
+ }
+
+ event_queue = al_create_event_queue();
+ if (!event_queue) {
+ fprintf(stdout, "failed to create event_queue!\n");
+ al_destroy_display(display);
+ exit(1);
+ }
+
+ al_register_event_source(event_queue, al_get_display_event_source(display));
+ al_register_event_source(event_queue, al_get_mouse_event_source());
+ al_register_event_source(event_queue, al_get_keyboard_event_source());
+
+ NkAllegro5Font *font;
+ font = nk_allegro5_font_create_from_file("../../../extra_font/Roboto-Regular.ttf", 12, 0);
+ struct nk_context *ctx;
+
+ ctx = nk_allegro5_init(font, display, 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(1)
+ {
+ ALLEGRO_EVENT ev;
+ ALLEGRO_TIMEOUT timeout;
+ al_init_timeout(&timeout, 0.06);
+
+ bool get_event = al_wait_for_event_until(event_queue, &ev, &timeout);
+
+ if (get_event && ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
+ break;
+ }
+
+ /* Very Important: Always do nk_input_begin / nk_input_end even if
+ there are no events, otherwise internal nuklear state gets messed up */
+ nk_input_begin(ctx);
+ if (get_event) {
+ while (get_event) {
+ nk_allegro5_handle_event(&ev);
+ get_event = al_get_next_event(event_queue, &ev);
+ }
+ }
+ 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);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ overview(ctx);
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ al_clear_to_color(al_map_rgb(19, 43, 81));
+ /* IMPORTANT: `nk_allegro5_render` changes the target backbuffer
+ to the display set at initialization and does not restore it.
+ Change it if you want to draw somewhere else. */
+ nk_allegro5_render();
+ al_flip_display();
+ }
+
+ nk_allegro5_font_del(font);
+ nk_allegro5_shutdown();
+ al_destroy_display(display);
+ al_destroy_event_queue(event_queue);
+ return 0;
+}
+
diff --git a/nuklear/demo/allegro5/nuklear_allegro5.h b/nuklear/demo/allegro5/nuklear_allegro5.h
new file mode 100644
index 0000000..f396600
--- /dev/null
+++ b/nuklear/demo/allegro5/nuklear_allegro5.h
@@ -0,0 +1,459 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_ALLEGRO5_H_
+#define NK_ALLEGRO5_H_
+
+#include <string.h>
+#include <allegro5/allegro.h>
+#include <allegro5/allegro_image.h>
+#include <allegro5/allegro_primitives.h>
+#include <allegro5/allegro_font.h>
+#include <allegro5/allegro_ttf.h>
+
+typedef struct NkAllegro5Font NkAllegro5Font;
+NK_API struct nk_context* nk_allegro5_init(NkAllegro5Font *font, ALLEGRO_DISPLAY *dsp,
+ unsigned int width, unsigned int height);
+NK_API void nk_allegro5_handle_event(ALLEGRO_EVENT *ev);
+NK_API void nk_allegro5_shutdown(void);
+NK_API void nk_allegro5_render(void);
+
+/* Fonts. We wrap normal allegro fonts in some nuklear book keeping */
+NK_API NkAllegro5Font* nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags);
+NK_API void nk_allegro5_font_del(NkAllegro5Font *font);
+NK_API void nk_allegro5_font_set_font(NkAllegro5Font *font);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_ALLEGRO5_IMPLEMENTATION
+
+#ifndef NK_ALLEGRO5_TEXT_MAX
+#define NK_ALLEGRO5_TEXT_MAX 256
+#endif
+
+
+struct NkAllegro5Font {
+ struct nk_user_font nk;
+ int height;
+ ALLEGRO_FONT *font;
+};
+
+static struct nk_allegro5 {
+ ALLEGRO_DISPLAY *dsp;
+ unsigned int width;
+ unsigned int height;
+ int is_touch_down;
+ int touch_down_id;
+ struct nk_context ctx;
+ struct nk_buffer cmds;
+} allegro5;
+
+
+/* Flags are identical to al_load_font() flags argument */
+NK_API NkAllegro5Font*
+nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags)
+{
+ if (!al_init_image_addon()) {
+ fprintf(stdout, "Unable to initialize required allegro5 image addon\n");
+ exit(1);
+ }
+ if (!al_init_font_addon()) {
+ fprintf(stdout, "Unable to initialize required allegro5 font addon\n");
+ exit(1);
+ }
+ if (!al_init_ttf_addon()) {
+ fprintf(stdout, "Unable to initialize required allegro5 TTF font addon\n");
+ exit(1);
+ }
+ NkAllegro5Font *font = (NkAllegro5Font*)calloc(1, sizeof(NkAllegro5Font));
+
+ font->font = al_load_font(file_name, font_size, flags);
+ if (font->font == NULL) {
+ fprintf(stdout, "Unable to load font file: %s\n", file_name);
+ return NULL;
+ }
+ font->height = al_get_font_line_height(font->font);
+ return font;
+}
+
+static float
+nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;
+ if (!font || !text) {
+ return 0;
+ }
+ /* We must copy into a new buffer with exact length null-terminated
+ as nuklear uses variable size buffers and al_get_text_width doesn't
+ accept a length, it infers length from null-termination
+ (which is unsafe API design by allegro devs!) */
+ char strcpy[len+1];
+ strncpy((char*)&strcpy, text, len);
+ strcpy[len] = '\0';
+ return al_get_text_width(font->font, strcpy);
+}
+
+NK_API void
+nk_allegro5_font_set_font(NkAllegro5Font *allegro5font)
+{
+ struct nk_user_font *font = &allegro5font->nk;
+ font->userdata = nk_handle_ptr(allegro5font);
+ font->height = (float)allegro5font->height;
+ font->width = nk_allegro5_font_get_text_width;
+ nk_style_set_font(&allegro5.ctx, font);
+}
+
+NK_API void
+nk_allegro5_font_del(NkAllegro5Font *font)
+{
+ if(!font) return;
+ al_destroy_font(font->font);
+ free(font);
+}
+
+static ALLEGRO_COLOR
+nk_color_to_allegro_color(struct nk_color color)
+{
+ return al_map_rgba((unsigned char)color.r, (unsigned char)color.g,
+ (unsigned char)color.b, (unsigned char)color.a);
+}
+
+NK_API void
+nk_allegro5_render()
+{
+ const struct nk_command *cmd;
+
+ al_set_target_backbuffer(allegro5.dsp);
+
+ nk_foreach(cmd, &allegro5.ctx)
+ {
+ ALLEGRO_COLOR color;
+ switch (cmd->type) {
+ case NK_COMMAND_NOP: break;
+ case NK_COMMAND_SCISSOR: {
+ const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+ al_set_clipping_rectangle((int)s->x, (int)s->y, (int)s->w, (int)s->h);
+ } break;
+ case NK_COMMAND_LINE: {
+ const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+ color = nk_color_to_allegro_color(l->color);
+ al_draw_line((float)l->begin.x, (float)l->begin.y, (float)l->end.x,
+ (float)l->end.y, color, (float)l->line_thickness);
+ } break;
+ case NK_COMMAND_RECT: {
+ const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+ color = nk_color_to_allegro_color(r->color);
+ al_draw_rounded_rectangle((float)r->x, (float)r->y, (float)(r->x + r->w),
+ (float)(r->y + r->h), (float)r->rounding, (float)r->rounding, color,
+ (float)r->line_thickness);
+ } break;
+ case NK_COMMAND_RECT_FILLED: {
+ const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+ color = nk_color_to_allegro_color(r->color);
+ al_draw_filled_rounded_rectangle((float)r->x, (float)r->y,
+ (float)(r->x + r->w), (float)(r->y + r->h), (float)r->rounding,
+ (float)r->rounding, color);
+ } break;
+ case NK_COMMAND_CIRCLE: {
+ const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+ color = nk_color_to_allegro_color(c->color);
+ float xr, yr;
+ xr = (float)c->w/2;
+ yr = (float)c->h/2;
+ al_draw_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
+ xr, yr, color, (float)c->line_thickness);
+ } break;
+ case NK_COMMAND_CIRCLE_FILLED: {
+ const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+ color = nk_color_to_allegro_color(c->color);
+ float xr, yr;
+ xr = (float)c->w/2;
+ yr = (float)c->h/2;
+ al_draw_filled_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,
+ xr, yr, color);
+ } break;
+ case NK_COMMAND_TRIANGLE: {
+ const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+ color = nk_color_to_allegro_color(t->color);
+ al_draw_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, (float)t->b.y,
+ (float)t->c.x, (float)t->c.y, color, (float)t->line_thickness);
+ } break;
+ case NK_COMMAND_TRIANGLE_FILLED: {
+ const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+ color = nk_color_to_allegro_color(t->color);
+ al_draw_filled_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x,
+ (float)t->b.y, (float)t->c.x, (float)t->c.y, color);
+ } break;
+ case NK_COMMAND_POLYGON: {
+ const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;
+ color = nk_color_to_allegro_color(p->color);
+ int i;
+ float vertices[p->point_count * 2];
+ for (i = 0; i < p->point_count; i++) {
+ vertices[i*2] = p->points[i].x;
+ vertices[(i*2) + 1] = p->points[i].y;
+ }
+ al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
+ (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED,
+ color, (float)p->line_thickness, 0.0);
+ } break;
+ case NK_COMMAND_POLYGON_FILLED: {
+ const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+ color = nk_color_to_allegro_color(p->color);
+ int i;
+ float vertices[p->point_count * 2];
+ for (i = 0; i < p->point_count; i++) {
+ vertices[i*2] = p->points[i].x;
+ vertices[(i*2) + 1] = p->points[i].y;
+ }
+ al_draw_filled_polygon((const float*)&vertices, (int)p->point_count, color);
+ } break;
+ case NK_COMMAND_POLYLINE: {
+ const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+ color = nk_color_to_allegro_color(p->color);
+ int i;
+ float vertices[p->point_count * 2];
+ for (i = 0; i < p->point_count; i++) {
+ vertices[i*2] = p->points[i].x;
+ vertices[(i*2) + 1] = p->points[i].y;
+ }
+ al_draw_polyline((const float*)&vertices, (2 * sizeof(float)),
+ (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND,
+ color, (float)p->line_thickness, 0.0);
+ } break;
+ case NK_COMMAND_TEXT: {
+ const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+ color = nk_color_to_allegro_color(t->foreground);
+ NkAllegro5Font *font = (NkAllegro5Font*)t->font->userdata.ptr;
+ al_draw_text(font->font,
+ color, (float)t->x, (float)t->y, 0,
+ (const char*)t->string);
+ } break;
+ case NK_COMMAND_CURVE: {
+ const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+ color = nk_color_to_allegro_color(q->color);
+ float points[8];
+ points[0] = (float)q->begin.x;
+ points[1] = (float)q->begin.y;
+ points[2] = (float)q->ctrl[0].x;
+ points[3] = (float)q->ctrl[0].y;
+ points[4] = (float)q->ctrl[1].x;
+ points[5] = (float)q->ctrl[1].y;
+ points[6] = (float)q->end.x;
+ points[7] = (float)q->end.y;
+ al_draw_spline(points, color, (float)q->line_thickness);
+ } break;
+ case NK_COMMAND_ARC: {
+ const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;
+ color = nk_color_to_allegro_color(a->color);
+ al_draw_arc((float)a->cx, (float)a->cy, (float)a->r, a->a[0],
+ a->a[1], color, (float)a->line_thickness);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_IMAGE:
+ case NK_COMMAND_ARC_FILLED:
+ default: break;
+ }
+ }
+ nk_clear(&allegro5.ctx);
+}
+
+NK_API void
+nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
+{
+ struct nk_context *ctx = &allegro5.ctx;
+ switch (ev->type) {
+ case ALLEGRO_EVENT_DISPLAY_RESIZE: {
+ allegro5.width = (unsigned int)ev->display.width;
+ allegro5.height = (unsigned int)ev->display.height;
+ al_acknowledge_resize(ev->display.source);
+ } break;
+ case ALLEGRO_EVENT_MOUSE_AXES: {
+ nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);
+ if (ev->mouse.dz != 0) {
+ nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision()));
+ }
+ } break;
+ case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
+ case ALLEGRO_EVENT_MOUSE_BUTTON_UP: {
+ int button = NK_BUTTON_LEFT;
+ if (ev->mouse.button == 2) {
+ button = NK_BUTTON_RIGHT;
+ }
+ else if (ev->mouse.button == 3) {
+ button = NK_BUTTON_MIDDLE;
+ }
+ nk_input_button(ctx, button, ev->mouse.x, ev->mouse.y, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
+ } break;
+ /* This essentially converts touch events to mouse events */
+ case ALLEGRO_EVENT_TOUCH_BEGIN:
+ case ALLEGRO_EVENT_TOUCH_END: {
+ /* We only acknowledge one touch at a time. Otherwise, each touch
+ would be manipulating multiple nuklear elements, as if there
+ were multiple mouse cursors */
+ if (allegro5.is_touch_down && allegro5.touch_down_id != ev->touch.id) {
+ return;
+ }
+ if (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN) {
+ allegro5.is_touch_down = 1;
+ allegro5.touch_down_id = ev->touch.id;
+ /* FIXME: This is a hack to properly simulate
+ touches as a mouse with nuklear. If you instantly jump
+ from one place to another without an nk_input_end(), it
+ confuses the nuklear state. nuklear expects smooth mouse
+ movements, which is unlike a touch screen */
+ nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
+ nk_input_end(ctx);
+ nk_input_begin(ctx);
+ }
+ else {
+ allegro5.is_touch_down = 0;
+ allegro5.touch_down_id = -1;
+ }
+ nk_input_button(ctx, NK_BUTTON_LEFT, (int)ev->touch.x, (int)ev->touch.y, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
+ } break;
+ case ALLEGRO_EVENT_TOUCH_MOVE: {
+ /* Only acknowledge movements of a single touch, we are
+ simulating a mouse cursor */
+ if (!allegro5.is_touch_down || allegro5.touch_down_id != ev->touch.id) {
+ return;
+ }
+ nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);
+ } break;
+ case ALLEGRO_EVENT_KEY_DOWN:
+ case ALLEGRO_EVENT_KEY_UP: {
+ int kc = ev->keyboard.keycode;
+ int down = ev->type == ALLEGRO_EVENT_KEY_DOWN;
+
+ if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (kc == ALLEGRO_KEY_DELETE) nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (kc == ALLEGRO_KEY_ENTER) nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (kc == ALLEGRO_KEY_TAB) nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (kc == ALLEGRO_KEY_LEFT) nk_input_key(ctx, NK_KEY_LEFT, down);
+ else if (kc == ALLEGRO_KEY_RIGHT) nk_input_key(ctx, NK_KEY_RIGHT, down);
+ else if (kc == ALLEGRO_KEY_UP) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (kc == ALLEGRO_KEY_DOWN) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (kc == ALLEGRO_KEY_BACKSPACE) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (kc == ALLEGRO_KEY_ESCAPE) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);
+ else if (kc == ALLEGRO_KEY_PGUP) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (kc == ALLEGRO_KEY_PGDN) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (kc == ALLEGRO_KEY_HOME) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (kc == ALLEGRO_KEY_END) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ }
+ } break;
+ case ALLEGRO_EVENT_KEY_CHAR: {
+ int kc = ev->keyboard.keycode;
+ int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ||
+ (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND);
+
+ if (kc == ALLEGRO_KEY_C && control_mask) {
+ nk_input_key(ctx, NK_KEY_COPY, 1);
+ } else if (kc == ALLEGRO_KEY_V && control_mask) {
+ nk_input_key(ctx, NK_KEY_PASTE, 1);
+ } else if (kc == ALLEGRO_KEY_X && control_mask) {
+ nk_input_key(ctx, NK_KEY_CUT, 1);
+ } else if (kc == ALLEGRO_KEY_Z && control_mask) {
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, 1);
+ } else if (kc == ALLEGRO_KEY_R && control_mask) {
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, 1);
+ } else if (kc == ALLEGRO_KEY_A && control_mask) {
+ nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1);
+ } else {
+ if (kc != ALLEGRO_KEY_BACKSPACE &&
+ kc != ALLEGRO_KEY_LEFT &&
+ kc != ALLEGRO_KEY_RIGHT &&
+ kc != ALLEGRO_KEY_UP &&
+ kc != ALLEGRO_KEY_DOWN &&
+ kc != ALLEGRO_KEY_HOME &&
+ kc != ALLEGRO_KEY_DELETE &&
+ kc != ALLEGRO_KEY_ENTER &&
+ kc != ALLEGRO_KEY_END &&
+ kc != ALLEGRO_KEY_ESCAPE &&
+ kc != ALLEGRO_KEY_PGDN &&
+ kc != ALLEGRO_KEY_PGUP) {
+ nk_input_unicode(ctx, ev->keyboard.unichar);
+ }
+ }
+ } break;
+ default: break;
+ }
+}
+
+NK_INTERN void
+nk_allegro5_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ char *text = al_get_clipboard_text(allegro5.dsp);
+ if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+ al_free(text);
+}
+
+NK_INTERN void
+nk_allegro5_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ al_set_clipboard_text(allegro5.dsp, str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_allegro5_init(NkAllegro5Font *allegro5font, ALLEGRO_DISPLAY *dsp,
+ unsigned int width, unsigned int height)
+{
+ if (!al_init_primitives_addon()) {
+ fprintf(stdout, "Unable to initialize required allegro5 primitives addon\n");
+ exit(1);
+ }
+
+ struct nk_user_font *font = &allegro5font->nk;
+ font->userdata = nk_handle_ptr(allegro5font);
+ font->height = (float)allegro5font->height;
+ font->width = nk_allegro5_font_get_text_width;
+
+ allegro5.dsp = dsp;
+ allegro5.width = width;
+ allegro5.height = height;
+ allegro5.is_touch_down = 0;
+ allegro5.touch_down_id = -1;
+
+ nk_init_default(&allegro5.ctx, font);
+ allegro5.ctx.clip.copy = nk_allegro5_clipboard_copy;
+ allegro5.ctx.clip.paste = nk_allegro5_clipboard_paste;
+ allegro5.ctx.clip.userdata = nk_handle_ptr(0);
+ return &allegro5.ctx;
+}
+
+NK_API
+void nk_allegro5_shutdown(void)
+{
+ nk_free(&allegro5.ctx);
+ memset(&allegro5, 0, sizeof(allegro5));
+}
+
+#endif /* NK_ALLEGRO5_IMPLEMENTATION */
+
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..a7abf1d
--- /dev/null
+++ b/nuklear/demo/d3d11/main.c
@@ -0,0 +1,299 @@
+/* nuklear - 1.32.0 - 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 defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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, (void **)&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_colorf bg;
+
+ 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.style = CS_DBLCLKS;
+ 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/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_d3d11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+ /* style.c */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ ID3D11DeviceContext_ClearRenderTargetView(context, rt_view, &bg.r);
+ 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..7097d98
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11.h
@@ -0,0 +1,622 @@
+/*
+ * Nuklear - 1.32.0 - 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_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ 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, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+
+ case WM_LBUTTONDBLCLK:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ 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/d3d9/build.bat b/nuklear/demo/d3d9/build.bat
new file mode 100644
index 0000000..726b6f6
--- /dev/null
+++ b/nuklear/demo/d3d9/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 /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib d3d9.lib /link /incremental:no
diff --git a/nuklear/demo/d3d9/main.c b/nuklear/demo/d3d9/main.c
new file mode 100644
index 0000000..b329e2b
--- /dev/null
+++ b/nuklear/demo/d3d9/main.c
@@ -0,0 +1,313 @@
+/* nuklear - 1.32.0 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d9.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_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D9_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d9.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 defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static IDirect3DDevice9 *device;
+static IDirect3DDevice9Ex *deviceEx;
+static D3DPRESENT_PARAMETERS present;
+
+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 (device)
+ {
+ UINT width = LOWORD(lparam);
+ UINT height = HIWORD(lparam);
+ if (width != 0 && height != 0 &&
+ (width != present.BackBufferWidth || height != present.BackBufferHeight))
+ {
+ nk_d3d9_release();
+ present.BackBufferWidth = width;
+ present.BackBufferHeight = height;
+ HRESULT hr = IDirect3DDevice9_Reset(device, &present);
+ NK_ASSERT(SUCCEEDED(hr));
+ nk_d3d9_resize(width, height);
+ }
+ }
+ break;
+ }
+
+ if (nk_d3d9_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+static void create_d3d9_device(HWND wnd)
+{
+ HRESULT hr;
+
+ present.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ present.BackBufferWidth = WINDOW_WIDTH;
+ present.BackBufferHeight = WINDOW_HEIGHT;
+ present.BackBufferFormat = D3DFMT_X8R8G8B8;
+ present.BackBufferCount = 1;
+ present.MultiSampleType = D3DMULTISAMPLE_NONE;
+ present.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ present.hDeviceWindow = wnd;
+ present.EnableAutoDepthStencil = TRUE;
+ present.AutoDepthStencilFormat = D3DFMT_D24S8;
+ present.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
+ present.Windowed = TRUE;
+
+ {/* first try to create Direct3D9Ex device if possible (on Windows 7+) */
+ typedef HRESULT WINAPI Direct3DCreate9ExPtr(UINT, IDirect3D9Ex**);
+ Direct3DCreate9ExPtr *Direct3DCreate9Ex = (void *)GetProcAddress(GetModuleHandleA("d3d9.dll"), "Direct3DCreate9Ex");
+ if (Direct3DCreate9Ex) {
+ IDirect3D9Ex *d3d9ex;
+ if (SUCCEEDED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex))) {
+ hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+ &present, NULL, &deviceEx);
+ if (SUCCEEDED(hr)) {
+ device = (IDirect3DDevice9 *)deviceEx;
+ } else {
+ /* hardware vertex processing not supported, no big deal
+ retry with software vertex processing */
+ hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+ &present, NULL, &deviceEx);
+ if (SUCCEEDED(hr)) {
+ device = (IDirect3DDevice9 *)deviceEx;
+ }
+ }
+ IDirect3D9Ex_Release(d3d9ex);
+ }
+ }
+ }
+
+ if (!device) {
+ /* otherwise do regular D3D9 setup */
+ IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+
+ hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+ &present, &device);
+ if (FAILED(hr)) {
+ /* hardware vertex processing not supported, no big deal
+ retry with software vertex processing */
+ hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+ &present, &device);
+ NK_ASSERT(SUCCEEDED(hr));
+ }
+ IDirect3D9_Release(d3d9);
+ }
+}
+
+int main(void)
+{
+ struct nk_context *ctx;
+ struct nk_colorf bg;
+
+ WNDCLASSW wc;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ int running = 1;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.style = CS_DBLCLKS;
+ 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);
+
+ create_d3d9_device(wnd);
+
+ /* GUI */
+ ctx = nk_d3d9_init(device, WINDOW_WIDTH, WINDOW_HEIGHT);
+ /* 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_d3d9_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/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_d3d9_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+ /* style.c */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {
+ HRESULT hr;
+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
+ D3DCOLOR_COLORVALUE(bg.a, bg.r, bg.g, bg.b), 0.0f, 0);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ hr = IDirect3DDevice9_BeginScene(device);
+ NK_ASSERT(SUCCEEDED(hr));
+ nk_d3d9_render(NK_ANTI_ALIASING_ON);
+ hr = IDirect3DDevice9_EndScene(device);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ if (deviceEx) {
+ hr = IDirect3DDevice9Ex_PresentEx(deviceEx, NULL, NULL, NULL, NULL, 0);
+ } else {
+ hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+ }
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG || hr == D3DERR_DEVICEREMOVED) {
+ /* to recover from this, you'll need to recreate device and all the resources */
+ MessageBoxW(NULL, L"D3D9 device is lost or removed!", L"Error", 0);
+ break;
+ } else if (hr == S_PRESENT_OCCLUDED) {
+ /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+ Sleep(10);
+ }
+ NK_ASSERT(SUCCEEDED(hr));
+ }
+ }
+ nk_d3d9_shutdown();
+ if (deviceEx)IDirect3DDevice9Ex_Release(deviceEx);
+ else IDirect3DDevice9_Release(device);
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
diff --git a/nuklear/demo/d3d9/nuklear_d3d9.h b/nuklear/demo/d3d9/nuklear_d3d9.h
new file mode 100644
index 0000000..fd8d176
--- /dev/null
+++ b/nuklear/demo/d3d9/nuklear_d3d9.h
@@ -0,0 +1,543 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D9_H_
+#define NK_D3D9_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct IDirect3DDevice9 IDirect3DDevice9;
+
+NK_API struct nk_context *nk_d3d9_init(IDirect3DDevice9 *device, int width, int height);
+NK_API void nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_d3d9_font_stash_end(void);
+NK_API int nk_d3d9_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_d3d9_render(enum nk_anti_aliasing);
+NK_API void nk_d3d9_release(void);
+NK_API void nk_d3d9_resize(int width, int height);
+NK_API void nk_d3d9_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D9_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d9.h>
+
+#include <stddef.h>
+#include <string.h>
+
+struct nk_d3d9_vertex {
+ /* D3d9 FFP requires three coordinate position, but nuklear writes only 2 elements
+ projection matrix doesn't use z coordinate => so it can be any value.
+ Member order here is important! Do not rearrange them! */
+ float position[3];
+ nk_uchar col[4];
+ float uv[2];
+};
+
+static struct {
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_buffer cmds;
+
+ struct nk_draw_null_texture null;
+
+ D3DVIEWPORT9 viewport;
+ D3DMATRIX projection;
+ IDirect3DDevice9 *device;
+ IDirect3DTexture9 *texture;
+ IDirect3DStateBlock9 *state;
+} d3d9;
+
+NK_API void
+nk_d3d9_create_state()
+{
+ HRESULT hr;
+
+ hr = IDirect3DDevice9_BeginStateBlock(d3d9.device);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ /* vertex format */
+ IDirect3DDevice9_SetFVF(d3d9.device, D3DFVF_XYZ + D3DFVF_DIFFUSE + D3DFVF_TEX1);
+
+ /* blend state */
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ALPHABLENDENABLE, TRUE);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_BLENDOP, D3DBLENDOP_ADD);
+
+ /* render state */
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_LIGHTING, FALSE);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZENABLE, FALSE);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZWRITEENABLE, FALSE);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_CULLMODE, D3DCULL_NONE);
+ IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SCISSORTESTENABLE, TRUE);
+
+ /* sampler state */
+ IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+ IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+
+ /* texture stage state */
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+
+ hr = IDirect3DDevice9_EndStateBlock(d3d9.device, &d3d9.state);
+ NK_ASSERT(SUCCEEDED(hr));
+}
+
+NK_API void
+nk_d3d9_render(enum nk_anti_aliasing AA)
+{
+ HRESULT hr;
+
+ nk_d3d9_create_state();
+
+ hr = IDirect3DStateBlock9_Apply(d3d9.state);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ /* projection matrix */
+ IDirect3DDevice9_SetTransform(d3d9.device, D3DTS_PROJECTION, &d3d9.projection);
+
+ /* viewport */
+ IDirect3DDevice9_SetViewport(d3d9.device, &d3d9.viewport);
+
+ /* convert from command queue into draw list and draw to screen */
+ {
+ struct nk_buffer vbuf, ebuf;
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ UINT vertex_count;
+
+ /* 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_d3d9_vertex, position)},
+ {NK_VERTEX_COLOR, NK_FORMAT_B8G8R8A8, NK_OFFSETOF(struct nk_d3d9_vertex, col)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d9_vertex, uv)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ memset(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_d3d9_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_d3d9_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 = d3d9.null;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&d3d9.ctx, &d3d9.cmds, &vbuf, &ebuf, &config);
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index *)nk_buffer_memory_const(&ebuf);
+ vertex_count = (UINT)vbuf.needed / sizeof(struct nk_d3d9_vertex);
+
+ nk_draw_foreach(cmd, &d3d9.ctx, &d3d9.cmds)
+ {
+ RECT scissor;
+ if (!cmd->elem_count) continue;
+
+ hr = IDirect3DDevice9_SetTexture(d3d9.device, 0, (IDirect3DBaseTexture9 *)cmd->texture.ptr);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ 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);
+
+ hr = IDirect3DDevice9_SetScissorRect(d3d9.device, &scissor);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ NK_ASSERT(sizeof(nk_draw_index) == sizeof(NK_UINT16));
+ hr = IDirect3DDevice9_DrawIndexedPrimitiveUP(d3d9.device, D3DPT_TRIANGLELIST,
+ 0, vertex_count, cmd->elem_count/3, offset, D3DFMT_INDEX16,
+ nk_buffer_memory_const(&vbuf), sizeof(struct nk_d3d9_vertex));
+ NK_ASSERT(SUCCEEDED(hr));
+ offset += cmd->elem_count;
+ }
+
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ nk_clear(&d3d9.ctx);
+
+ IDirect3DStateBlock9_Apply(d3d9.state);
+ IDirect3DStateBlock9_Release(d3d9.state);
+}
+
+static void
+nk_d3d9_get_projection_matrix(int width, int height, float *result)
+{
+ const float L = 0.5f;
+ const float R = (float)width + 0.5f;
+ const float T = 0.5f;
+ const float B = (float)height + 0.5f;
+ 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.0f, 0.0f },
+ { (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f },
+ };
+ memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d9_release(void)
+{
+ IDirect3DTexture9_Release(d3d9.texture);
+}
+
+static void
+nk_d3d9_create_font_texture()
+{
+ int w, h, y;
+ const void *image;
+
+ HRESULT hr;
+ D3DLOCKED_RECT locked;
+
+ image = nk_font_atlas_bake(&d3d9.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+
+ hr = IDirect3DDevice9_CreateTexture(d3d9.device, w, h, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9.texture, NULL);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ hr = IDirect3DTexture9_LockRect(d3d9.texture, 0, &locked, NULL, 0);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ for (y = 0; y < h; y++) {
+ void *src = (char *)image + y * w * 4;
+ void *dst = (char *)locked.pBits + y * locked.Pitch;
+ memcpy(dst, src, w * 4);
+ }
+
+ hr = IDirect3DTexture9_UnlockRect(d3d9.texture, 0);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ nk_font_atlas_end(&d3d9.atlas, nk_handle_ptr(d3d9.texture), &d3d9.null);
+}
+
+NK_API void
+nk_d3d9_resize(int width, int height)
+{
+ if (d3d9.texture) {
+ nk_d3d9_create_font_texture();
+ }
+
+ nk_d3d9_create_state();
+
+ nk_d3d9_get_projection_matrix(width, height, &d3d9.projection.m[0][0]);
+ d3d9.viewport.Width = width;
+ d3d9.viewport.Height = height;
+}
+
+NK_API int
+nk_d3d9_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(&d3d9.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&d3d9.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&d3d9.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&d3d9.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&d3d9.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&d3d9.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&d3d9.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&d3d9.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&d3d9.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&d3d9.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&d3d9.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&d3d9.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&d3d9.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+
+ case WM_LBUTTONDBLCLK:
+ nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+nk_d3d9_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ (void)usr;
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) {
+ return;
+ }
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (!mem) {
+ CloseClipboard();
+ return;
+ }
+
+ SIZE_T size = GlobalSize(mem) - 1;
+ if (!size) {
+ CloseClipboard();
+ return;
+ }
+
+ LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+ if (!wstr) {
+ CloseClipboard();
+ return;
+ }
+
+ 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_d3d9_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+ (void)usr;
+ if (!OpenClipboard(NULL)) {
+ return;
+ }
+
+ 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_d3d9_init(IDirect3DDevice9 *device, int width, int height)
+{
+ d3d9.device = device;
+ IDirect3DDevice9_AddRef(device);
+
+ nk_init_default(&d3d9.ctx, 0);
+ d3d9.state = NULL;
+ d3d9.texture = NULL;
+ d3d9.ctx.clip.copy = nk_d3d9_clipboard_copy;
+ d3d9.ctx.clip.paste = nk_d3d9_clipboard_paste;
+ d3d9.ctx.clip.userdata = nk_handle_ptr(0);
+
+ nk_buffer_init_default(&d3d9.cmds);
+
+ /* viewport */
+ d3d9.viewport.X = 0;
+ d3d9.viewport.Y = 0;
+ d3d9.viewport.MinZ = 0.0f;
+ d3d9.viewport.MaxZ = 1.0f;
+
+ nk_d3d9_resize(width, height);
+
+ return &d3d9.ctx;
+}
+
+NK_API void
+nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&d3d9.atlas);
+ nk_font_atlas_begin(&d3d9.atlas);
+ *atlas = &d3d9.atlas;
+}
+
+NK_API void
+nk_d3d9_font_stash_end(void)
+{
+ nk_d3d9_create_font_texture();
+
+ if (d3d9.atlas.default_font)
+ nk_style_set_font(&d3d9.ctx, &d3d9.atlas.default_font->handle);
+}
+
+NK_API
+void nk_d3d9_shutdown(void)
+{
+ nk_d3d9_release();
+
+ nk_font_atlas_clear(&d3d9.atlas);
+ nk_buffer_free(&d3d9.cmds);
+ nk_free(&d3d9.ctx);
+}
+
+#endif
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..1755b9c
--- /dev/null
+++ b/nuklear/demo/gdi/main.c
@@ -0,0 +1,184 @@
+/* nuklear - 1.32.0 - 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 defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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.style = CS_DBLCLKS;
+ 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 */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ 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);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* 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..c875de1
--- /dev/null
+++ b/nuklear/demo/gdi/nuklear_gdi.h
@@ -0,0 +1,842 @@
+/*
+ * Nuklear - 1.32.0 - 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 void
+nk_create_image(struct nk_image * image, const char * frame_buffer, const int width, const int height)
+{
+ if (image && frame_buffer && (width > 0) && (height > 0))
+ {
+ image->w = width;
+ image->h = height;
+ image->region[0] = 0;
+ image->region[1] = 0;
+ image->region[2] = width;
+ image->region[3] = height;
+
+ INT row = ((width * 3 + 3) & ~3);
+ BITMAPINFO bi = { 0 };
+ bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bi.bmiHeader.biWidth = width;
+ bi.bmiHeader.biHeight = height;
+ bi.bmiHeader.biPlanes = 1;
+ bi.bmiHeader.biBitCount = 24;
+ bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biSizeImage = row * height;
+
+ LPBYTE lpBuf, pb = NULL;
+ HBITMAP hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);
+
+ pb = lpBuf + row * height;
+ unsigned char * src = (unsigned char *)frame_buffer;
+ for (int v = 0; v<height; v++)
+ {
+ pb -= row;
+ for (int i = 0; i < row; i += 3)
+ {
+ pb[i + 0] = src[0];
+ pb[i + 1] = src[1];
+ pb[i + 2] = src[2];
+ src += 3;
+ }
+ }
+ SetDIBits(NULL, hbm, 0, height, lpBuf, &bi, DIB_RGB_COLORS);
+ image->handle.ptr = hbm;
+ }
+}
+
+static void
+nk_delete_image(struct nk_image * image)
+{
+ if (image && image->handle.id != 0)
+ {
+ HBITMAP hbm = image->handle.ptr;
+ DeleteObject(hbm);
+ memset(image, 0, sizeof(struct nk_image));
+ }
+}
+
+static void
+nk_gdi_draw_image(short x, short y, unsigned short w, unsigned short h,
+ struct nk_image img, struct nk_color col)
+{
+ HBITMAP hbm = img.handle.ptr;
+ HDC hDCBits;
+ BITMAP bitmap;
+
+ if (!gdi.memory_dc || !hbm)
+ return;
+
+ hDCBits = CreateCompatibleDC(gdi.memory_dc);
+ GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap);
+ SelectObject(hDCBits, hbm);
+ StretchBlt(gdi.memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
+ DeleteDC(hDCBits);
+}
+
+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);
+ }
+
+ HGDIOBJ br = SelectObject(dc, GetStockObject(NULL_BRUSH));
+ if (r == 0) {
+ Rectangle(dc, x, y, x + w, y + h);
+ } else {
+ RoundRect(dc, x, y, x + w, y + h, r, r);
+ }
+ SelectObject(dc, br);
+
+ 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 = HIWORD(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_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ 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, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+
+ case WM_LBUTTONDBLCLK:
+ nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ 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: {
+ const struct nk_command_image *i = (const struct nk_command_image *)cmd;
+ nk_gdi_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);
+ } break;
+ 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..0f24655
--- /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 /D_CRT_SECURE_NO_DEPRECATE main.c user32.lib gdiplus.lib shlwapi.lib /link /incremental:no
diff --git a/nuklear/demo/gdip/main.c b/nuklear/demo/gdip/main.c
new file mode 100644
index 0000000..a90a0cf
--- /dev/null
+++ b/nuklear/demo/gdip/main.c
@@ -0,0 +1,178 @@
+/* nuklear - 1.32.0 - 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
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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.style = CS_DBLCLKS;
+ 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 */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ 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);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* 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..8a6c8d4
--- /dev/null
+++ b/nuklear/demo/gdip/nuklear_gdip.h
@@ -0,0 +1,1175 @@
+/*
+ * Nuklear - 1.40.8 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2017 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GDIP_H_
+#define NK_GDIP_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <shlwapi.h>
+
+/* font */
+typedef struct GdipFont GdipFont;
+NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
+NK_API GdipFont* nk_gdipfont_create_from_file(const WCHAR* filename, int size);
+NK_API GdipFont* nk_gdipfont_create_from_memory(const void* membuf, int membufSize, 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);
+
+/* image */
+NK_API struct nk_image nk_gdip_load_image_from_file(const WCHAR* filename);
+NK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, nk_uint membufSize);
+NK_API void nk_gdip_image_free(struct nk_image image);
+
+#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);
+
+GpStatus WINGDIPAPI
+GdipGetImageWidth(GpImage *image, UINT *width);
+
+GpStatus WINGDIPAPI
+GdipGetImageHeight(GpImage *image, UINT *height);
+
+GpStatus WINGDIPAPI
+GdipLoadImageFromFile(GDIPCONST WCHAR* filename, GpImage **image);
+
+GpStatus WINGDIPAPI
+GdipLoadImageFromStream(IStream* stream, GpImage **image);
+
+/* 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);
+
+GpStatus WINGDIPAPI
+GdipPrivateAddMemoryFont(GpFontCollection* fontCollection,
+ GDIPCONST void* memory, INT length);
+
+GpStatus WINGDIPAPI
+GdipPrivateAddFontFile(GpFontCollection* fontCollection,
+ GDIPCONST WCHAR* filename);
+
+GpStatus WINGDIPAPI
+GdipNewPrivateFontCollection(GpFontCollection** fontCollection);
+
+GpStatus WINGDIPAPI
+GdipDeletePrivateFontCollection(GpFontCollection** fontCollection);
+
+GpStatus WINGDIPAPI
+GdipGetFontCollectionFamilyList(GpFontCollection* fontCollection,
+ INT numSought, GpFontFamily* gpfamilies[], INT* numFound);
+
+GpStatus WINGDIPAPI
+GdipGetFontCollectionFamilyCount(GpFontCollection* fontCollection, INT* numFound);
+
+
+/* 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
+GdipDrawImageRectI(GpGraphics *graphics, GpImage *image, INT x, INT y,
+ INT width, INT height);
+
+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);
+
+LWSTDAPI_(IStream *) SHCreateMemStream(const BYTE *pInit, _In_ UINT cbInit);
+
+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;
+ GpFontCollection *fontCollection[10];
+ INT curFontCollection;
+
+ 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 + r, y, x + w - r, y);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + r, x + w, y + h - r);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x, y + r, x, y + h - r);
+ GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + r, y + h, x + w - r, 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, r, h - d);
+ GdipFillRectangleI(gdip.memory, gdip.brush, x + w - r, y + r, r, 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(cfg));
+ GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush);
+}
+
+static void
+nk_gdip_draw_image(short x, short y, unsigned short w, unsigned short h,
+ struct nk_image img, struct nk_color col)
+{
+ GpImage *image = img.handle.ptr;
+ GdipDrawImageRectI(gdip.memory, image, x, y, w, h);
+}
+
+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);
+}
+
+static struct nk_image
+nk_gdip_image_to_nk(GpImage *image) {
+ struct nk_image img;
+ UINT uwidth, uheight;
+ img = nk_image_ptr( (void*)image );
+ GdipGetImageHeight(image, &uheight);
+ GdipGetImageWidth(image, &uwidth);
+ img.h = uheight;
+ img.w = uwidth;
+ return img;
+}
+
+struct nk_image
+nk_gdip_load_image_from_file(const WCHAR *filename)
+{
+ GpImage *image;
+ if (GdipLoadImageFromFile(filename, &image))
+ return nk_image_id(0);
+ return nk_gdip_image_to_nk(image);
+}
+
+struct nk_image
+nk_gdip_load_image_from_memory(const void *membuf, nk_uint membufSize)
+{
+ GpImage* image;
+ GpStatus status;
+ IStream *stream = SHCreateMemStream((const BYTE*)membuf, membufSize);
+ if (!stream)
+ return nk_image_id(0);
+
+ status = GdipLoadImageFromStream(stream, &image);
+ stream->lpVtbl->Release(stream);
+
+ if (status)
+ return nk_image_id(0);
+
+ return nk_gdip_image_to_nk(image);
+}
+
+void
+nk_gdip_image_free(struct nk_image image)
+{
+ if (!image.handle.ptr)
+ return;
+ GdipDisposeImage(image.handle.ptr);
+}
+
+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;
+}
+
+GpFontCollection*
+nk_gdip_getCurFontCollection(){
+ return gdip.fontCollection[gdip.curFontCollection];
+}
+
+GdipFont*
+nk_gdipfont_create_from_collection(int size){
+ GpFontFamily **families;
+ INT count;
+ GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont));
+ if( GdipGetFontCollectionFamilyCount(nk_gdip_getCurFontCollection(), &count) ) return NULL;
+ families = (GpFontFamily**)calloc(1, sizeof(GpFontFamily*));
+ if( !families ) return NULL;
+ if( GdipGetFontCollectionFamilyList(nk_gdip_getCurFontCollection(), count, families, &count) ) return NULL;
+ if( count < 1 ) return NULL;
+ if( GdipCreateFont(families[count-1], (REAL)size, FontStyleRegular, UnitPixel, &font->handle) ) return NULL;
+ free(families);
+ gdip.curFontCollection++;
+ return font;
+}
+
+GdipFont*
+nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size)
+{
+ if( !nk_gdip_getCurFontCollection() )
+ if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL;
+ if( GdipPrivateAddMemoryFont(nk_gdip_getCurFontCollection(), membuf, membufSize) ) return NULL;
+ return nk_gdipfont_create_from_collection(size);
+}
+
+GdipFont*
+nk_gdipfont_create_from_file(const WCHAR* filename, int size)
+{
+ if( !nk_gdip_getCurFontCollection() )
+ if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL;
+ if( GdipPrivateAddFontFile(nk_gdip_getCurFontCollection(), filename) ) return NULL;
+ return nk_gdipfont_create_from_collection(size);
+}
+
+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)
+{
+ int i;
+ 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);
+
+ for(i=0; i< sizeof(gdip.fontCollection)/sizeof(gdip.fontCollection[0]); i++)
+ gdip.fontCollection[i] = NULL;
+ nk_init_default(&gdip.ctx, NULL);
+ gdip.ctx.clip.copy = nk_gdip_clipbard_copy;
+ gdip.ctx.clip.paste = nk_gdip_clipbard_paste;
+ gdip.curFontCollection = 0;
+ 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_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ 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, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+
+ case WM_LBUTTONDBLCLK:
+ nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+NK_API void
+nk_gdip_shutdown(void)
+{
+ int i;
+ for(i=0; i< gdip.curFontCollection; i++)
+ GdipDeletePrivateFontCollection( &gdip.fontCollection[i] );
+ 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_prerender_gui(enum nk_anti_aliasing AA)
+{
+ 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_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_IMAGE: {
+ const struct nk_command_image *i = (const struct nk_command_image *)cmd;
+ nk_gdip_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_ARC:
+ case NK_COMMAND_ARC_FILLED:
+ default: break;
+ }
+ }
+}
+
+NK_API void
+nk_gdip_render_gui(enum nk_anti_aliasing AA)
+{
+ nk_gdip_prerender_gui(AA);
+ nk_gdip_blit(gdip.window);
+ nk_clear(&gdip.ctx);
+}
+
+NK_API void
+nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear)
+{
+ nk_gdip_clear(clear);
+ nk_gdip_render_gui(AA);
+}
+
+#endif
diff --git a/nuklear/demo/glfw_opengl2/Makefile b/nuklear/demo/glfw_opengl2/Makefile
new file mode 100644
index 0000000..c08d65f
--- /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 -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib
+ 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..5d68bb9
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/main.c
@@ -0,0 +1,182 @@
+/* nuklear - v1.32.0 - 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
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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_colorf bg;
+
+ /* 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);*/}
+
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ glfwGetWindowSize(win, &width, &height);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* 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);
+ 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..7724b25
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h
@@ -0,0 +1,381 @@
+/*
+ * Nuklear - v1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2017 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);
+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
+#ifndef NK_GLFW_DOUBLE_CLICK_LO
+#define NK_GLFW_DOUBLE_CLICK_LO 0.02
+#endif
+#ifndef NK_GLFW_DOUBLE_CLICK_HI
+#define NK_GLFW_DOUBLE_CLICK_HI 0.2
+#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;
+ struct nk_vec2 scroll;
+ double last_button_click;
+ int is_double_click_down;
+ struct nk_vec2 double_click_pos;
+} 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)
+{
+ /* 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.x += (float)xoff;
+ glfw.scroll.y += (float)yoff;
+}
+
+NK_API void
+nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+ double x, y;
+ if (button != GLFW_MOUSE_BUTTON_LEFT) return;
+ glfwGetCursorPos(window, &x, &y);
+ if (action == GLFW_PRESS) {
+ double dt = glfwGetTime() - glfw.last_button_click;
+ if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {
+ glfw.is_double_click_down = nk_true;
+ glfw.double_click_pos = nk_vec2((float)x, (float)y);
+ }
+ glfw.last_button_click = glfwGetTime();
+ } else glfw.is_double_click_down = nk_false;
+}
+
+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);
+ glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_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);
+
+ glfw.is_double_click_down = nk_false;
+ glfw.double_click_pos = nk_vec2(0, 0);
+
+ 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_V) == 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, (double)ctx->input.mouse.prev.x, (double)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_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down);
+ nk_input_scroll(ctx, glfw.scroll);
+ nk_input_end(&glfw.ctx);
+ glfw.text_len = 0;
+ glfw.scroll = nk_vec2(0,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..da95261
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/Makefile
@@ -0,0 +1,26 @@
+# 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)
+ GLFW3 := $(shell pkg-config --libs glfw3)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib
+ else
+ LIBS = $(GLFW3) -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..529e88c
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/main.c
@@ -0,0 +1,200 @@
+/* nuklear - 1.32.0 - 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
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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_colorf bg;
+
+ /* 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);*/}
+
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ glfwGetWindowSize(win, &width, &height);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* 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..8fe98fc
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h
@@ -0,0 +1,492 @@
+/*
+ * Nuklear - 1.32.0 - 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);
+NK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GLFW_GL3_IMPLEMENTATION
+
+#ifndef NK_GLFW_TEXT_MAX
+#define NK_GLFW_TEXT_MAX 256
+#endif
+#ifndef NK_GLFW_DOUBLE_CLICK_LO
+#define NK_GLFW_DOUBLE_CLICK_LO 0.02
+#endif
+#ifndef NK_GLFW_DOUBLE_CLICK_HI
+#define NK_GLFW_DOUBLE_CLICK_HI 0.2
+#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;
+ struct nk_vec2 scroll;
+ double last_button_click;
+ int is_double_click_down;
+ struct nk_vec2 double_click_pos;
+} 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;
+ struct nk_buffer vbuf, ebuf;
+ 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 */
+ 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.x += (float)xoff;
+ glfw.scroll.y += (float)yoff;
+}
+
+NK_API void
+nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+ double x, y;
+ if (button != GLFW_MOUSE_BUTTON_LEFT) return;
+ glfwGetCursorPos(window, &x, &y);
+ if (action == GLFW_PRESS) {
+ double dt = glfwGetTime() - glfw.last_button_click;
+ if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {
+ glfw.is_double_click_down = nk_true;
+ glfw.double_click_pos = nk_vec2((float)x, (float)y);
+ }
+ glfw.last_button_click = glfwGetTime();
+ } else glfw.is_double_click_down = nk_false;
+}
+
+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);
+ glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_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);
+ glfw.last_button_click = 0;
+ nk_glfw3_device_create();
+
+ glfw.is_double_click_down = nk_false;
+ glfw.double_click_pos = nk_vec2(0, 0);
+
+ 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]);
+
+#ifdef NK_GLFW_GL3_MOUSE_GRABBING
+ /* 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);
+#endif
+
+ 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_V) == 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);
+#ifdef NK_GLFW_GL3_MOUSE_GRABBING
+ 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;
+ }
+#endif
+ 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_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down);
+ nk_input_scroll(ctx, glfw.scroll);
+ nk_input_end(&glfw.ctx);
+ glfw.text_len = 0;
+ glfw.scroll = nk_vec2(0,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..d4f34c3
--- /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;
+ NK_ASSERT((nk_size)editor->node_count < NK_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;
+ NK_ASSERT((nk_size)editor->link_count < NK_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);
+ struct nk_panel *node = 0;
+
+ 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 */
+ 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..3c3f381
--- /dev/null
+++ b/nuklear/demo/overview.c
@@ -0,0 +1,1249 @@
+
+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 int scale_left = 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 (scale_left) window_flags |= NK_WINDOW_SCALE_LEFT;
+ 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);
+
+ /* menu #1 */
+ nk_layout_row_begin(ctx, NK_STATIC, 25, 5);
+ 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);
+ }
+ /* menu #2 */
+ nk_layout_row_push(ctx, 60);
+ if (nk_menu_begin_label(ctx, "ADVANCED", NK_TEXT_LEFT, nk_vec2(200, 600)))
+ {
+ enum menu_state {MENU_NONE,MENU_FILE, MENU_EDIT,MENU_VIEW,MENU_CHART};
+ static enum menu_state menu_state = MENU_NONE;
+ enum nk_collapse_states state;
+
+ state = (menu_state == MENU_FILE) ? NK_MAXIMIZED: NK_MINIMIZED;
+ if (nk_tree_state_push(ctx, NK_TREE_TAB, "FILE", &state)) {
+ menu_state = MENU_FILE;
+ nk_menu_item_label(ctx, "New", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Open", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Save", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Close", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Exit", NK_TEXT_LEFT);
+ nk_tree_pop(ctx);
+ } else menu_state = (menu_state == MENU_FILE) ? MENU_NONE: menu_state;
+
+ state = (menu_state == MENU_EDIT) ? NK_MAXIMIZED: NK_MINIMIZED;
+ if (nk_tree_state_push(ctx, NK_TREE_TAB, "EDIT", &state)) {
+ menu_state = MENU_EDIT;
+ nk_menu_item_label(ctx, "Copy", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Delete", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Cut", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Paste", NK_TEXT_LEFT);
+ nk_tree_pop(ctx);
+ } else menu_state = (menu_state == MENU_EDIT) ? MENU_NONE: menu_state;
+
+ state = (menu_state == MENU_VIEW) ? NK_MAXIMIZED: NK_MINIMIZED;
+ if (nk_tree_state_push(ctx, NK_TREE_TAB, "VIEW", &state)) {
+ menu_state = MENU_VIEW;
+ nk_menu_item_label(ctx, "About", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Options", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "Customize", NK_TEXT_LEFT);
+ nk_tree_pop(ctx);
+ } else menu_state = (menu_state == MENU_VIEW) ? MENU_NONE: menu_state;
+
+ state = (menu_state == MENU_CHART) ? NK_MAXIMIZED: NK_MINIMIZED;
+ if (nk_tree_state_push(ctx, NK_TREE_TAB, "CHART", &state)) {
+ size_t i = 0;
+ 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};
+ menu_state = MENU_CHART;
+ nk_layout_row_dynamic(ctx, 150, 1);
+ nk_chart_begin(ctx, NK_CHART_COLUMN, NK_LEN(values), 0, 50);
+ for (i = 0; i < NK_LEN(values); ++i)
+ nk_chart_push(ctx, values[i]);
+ nk_chart_end(ctx);
+ nk_tree_pop(ctx);
+ } else menu_state = (menu_state == MENU_CHART) ? MENU_NONE: menu_state;
+ nk_menu_end(ctx);
+ }
+ /* menu widgets */
+ 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_checkbox_label(ctx, "Scale Left", &scale_left);
+ 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: %zu" , 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_colorf combo_color2 = {0.509f, 0.705f, 0.2f, 1.0f};
+ 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, NK_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, nk_rgb_cf(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_propertyf(ctx, "#R:", 0, combo_color2.r, 1.0f, 0.01f,0.005f);
+ combo_color2.g = nk_propertyf(ctx, "#G:", 0, combo_color2.g, 1.0f, 0.01f,0.005f);
+ combo_color2.b = nk_propertyf(ctx, "#B:", 0, combo_color2.b, 1.0f, 0.01f,0.005f);
+ combo_color2.a = nk_propertyf(ctx, "#A:", 0, combo_color2.a, 1.0f, 0.01f,0.005f);
+ } else {
+ float hsva[4];
+ nk_colorf_hsva_fv(hsva, combo_color2);
+ hsva[0] = nk_propertyf(ctx, "#H:", 0, hsva[0], 1.0f, 0.01f,0.05f);
+ hsva[1] = nk_propertyf(ctx, "#S:", 0, hsva[1], 1.0f, 0.01f,0.05f);
+ hsva[2] = nk_propertyf(ctx, "#V:", 0, hsva[2], 1.0f, 0.01f,0.05f);
+ hsva[3] = nk_propertyf(ctx, "#A:", 0, hsva[3], 1.0f, 0.01f,0.05f);
+ combo_color2 = nk_hsva_colorfv(hsva);
+ }
+ 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, NK_LEN(values), 0, 50);
+ for (i = 0; i < NK_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",
+ "April", "May", "June", "July", "August", "September",
+ "October", "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 = NK_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)NK_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_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)
+ nk_tooltipf(ctx, "Value: %.2f", (float)cos((float)index*step));
+ 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)
+ nk_tooltipf(ctx, "Value: %.2f", (float)fabs(sin(step * (float)index)));
+ 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, 160, 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, 60, 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_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Row template:", NK_TEXT_LEFT);
+ nk_layout_row_template_begin(ctx, 30);
+ nk_layout_row_template_push_dynamic(ctx);
+ nk_layout_row_template_push_variable(ctx, 80);
+ nk_layout_row_template_push_static(ctx, 80);
+ nk_layout_row_template_end(ctx);
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ 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, 3);
+ 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_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) {
+ default: break;
+ 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..b73174a
--- /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..0fbf3ff
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/main.c
@@ -0,0 +1,198 @@
+/* nuklear - 1.32.0 - 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
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(void)
+{
+ /* Platform */
+ SDL_Window *win;
+ SDL_GLContext glContext;
+ int win_width, win_height;
+ int running = 1;
+
+ /* GUI */
+ struct nk_context *ctx;
+ struct nk_colorf bg;
+
+ /* 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)*/;}
+
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ SDL_GetWindowSize(win, &win_width, &win_height);
+ glViewport(0, 0, win_width, win_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* 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);
+ 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..62dc64e
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h
@@ -0,0 +1,346 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2017 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);
+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)
+{
+ /* 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) {
+ if (evt->button.clicks > 1)
+ nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ } else if (evt->button.button == SDL_BUTTON_MIDDLE)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else 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) {
+ /* mouse motion */
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ /* text input */
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ /* mouse wheel */
+ nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ nk_font_atlas_clear(&sdl.atlas);
+ nk_free(&sdl.ctx);
+ 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..c6fcb45
--- /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..9959d8a
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/main.c
@@ -0,0 +1,208 @@
+/* nuklear - 1.32.0 - 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 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int main(void)
+{
+ /* Platform */
+ SDL_Window *win;
+ SDL_GLContext glContext;
+ int win_width, win_height;
+ int running = 1;
+
+ /* GUI */
+ struct nk_context *ctx;
+ struct nk_colorf bg;
+
+ /* 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 */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ 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, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ printf("button pressed!\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ SDL_GetWindowSize(win, &win_width, &win_height);
+ glViewport(0, 0, win_width, win_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* 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..eb53ebb
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h
@@ -0,0 +1,442 @@
+/*
+ * Nuklear - 1.32.0 - 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;
+ struct nk_buffer vbuf, ebuf;
+
+ /* 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 */
+ 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) {
+ if (evt->button.clicks > 1)
+ nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ } else if (evt->button.button == SDL_BUTTON_MIDDLE)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else 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) {
+ /* mouse motion */
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ /* text input */
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ /* mouse wheel */
+ nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ 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/sdl_opengles2/Makefile b/nuklear/demo/sdl_opengles2/Makefile
new file mode 100644
index 0000000..7385305
--- /dev/null
+++ b/nuklear/demo/sdl_opengles2/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS += -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+UNAME_S := $(shell uname -s)
+ifeq ($(UNAME_S),Darwin)
+ LIBS = -lSDL2 -framework OpenGLES -lm
+else
+ LIBS = -lSDL2 -lGLESv2 -lm
+endif
+
+$(BIN): prepare
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
+
+web: prepare
+ emcc $(SRC) -Os -s USE_SDL=2 -o bin/index.html
+
+prepare:
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
diff --git a/nuklear/demo/sdl_opengles2/main.c b/nuklear/demo/sdl_opengles2/main.c
new file mode 100644
index 0000000..16a271a
--- /dev/null
+++ b/nuklear/demo/sdl_opengles2/main.c
@@ -0,0 +1,191 @@
+/* nuklear - 1.40.8 - 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>
+
+#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_GLES2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sdl_gles2.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
+ *
+ * ===============================================================*/
+
+
+/* Platform */
+SDL_Window *win;
+int running = nk_true;
+
+static void
+MainLoop(void* loopArg){
+ struct nk_context *ctx = (struct nk_context *)loopArg;
+
+ /* Input */
+ SDL_Event evt;
+ nk_input_begin(ctx);
+ while (SDL_PollEvent(&evt)) {
+ if (evt.type == SDL_QUIT) running = nk_false;
+ 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];
+ int win_width, win_height;
+ nk_color_fv(bg, nk_rgb(28,48,62));
+ 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);}
+}
+
+int main(int argc, char* argv[])
+{
+ /* GUI */
+ struct nk_context *ctx;
+ SDL_GLContext glContext;
+ /* SDL setup */
+ SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+ /*SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS); // - do NOT init SDL on GL ES 2 */
+ 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);
+
+ /* OpenGL setup */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ 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);*/
+
+#if defined(__EMSCRIPTEN__)
+ #include <emscripten.h>
+ emscripten_set_main_loop_arg(MainLoop, (void*)ctx, 0, nk_true);
+#else
+ while (running) MainLoop((void*)ctx);
+#endif
+
+ nk_sdl_shutdown();
+ SDL_GL_DeleteContext(glContext);
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return 0;
+}
+
diff --git a/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h b/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h
new file mode 100644
index 0000000..f96e610
--- /dev/null
+++ b/nuklear/demo/sdl_opengles2/nuklear_sdl_gles2.h
@@ -0,0 +1,443 @@
+/*
+ * Nuklear - 1.40.8 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2017 by Micha Mettke
+ * emscripten from 2016 by Chris Willcocks
+ * OpenGL ES 2.0 from 2017 by Dmitry Hrabrov a.k.a. DeXPeriX
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GLES2_H_
+#define NK_SDL_GLES2_H_
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengles2.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_GLES2_IMPLEMENTATION
+
+#include <string.h>
+
+struct nk_sdl_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, 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;
+ GLsizei vs;
+ size_t vp, vt, vc;
+};
+
+struct nk_sdl_vertex {
+ GLfloat position[2];
+ GLfloat 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;
+
+
+#define NK_SHADER_VERSION "#version 100\n"
+
+
+NK_API void
+nk_sdl_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "attribute vec2 Position;\n"
+ "attribute vec2 TexCoord;\n"
+ "attribute vec4 Color;\n"
+ "varying vec2 Frag_UV;\n"
+ "varying 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"
+ "varying vec2 Frag_UV;\n"
+ "varying vec4 Frag_Color;\n"
+ "void main(){\n"
+ " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);\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");
+ {
+ dev->vs = sizeof(struct nk_sdl_vertex);
+ dev->vp = offsetof(struct nk_sdl_vertex, position);
+ dev->vt = offsetof(struct nk_sdl_vertex, uv);
+ dev->vc = offsetof(struct nk_sdl_vertex, col);
+
+ /* Allocate buffers */
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 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;
+
+ /* Bind buffers */
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ {
+ /* buffer setup */
+ 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, dev->vs, (void*)dev->vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, dev->vs, (void*)dev->vc);
+ }
+
+ 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 = malloc((size_t)max_vertex_buffer);
+ elements = malloc((size_t)max_element_buffer);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sdl_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+ config.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);}
+ }
+ glBufferSubData(GL_ARRAY_BUFFER, 0, (size_t)max_vertex_buffer, vertices);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, (size_t)max_element_buffer, elements);
+ free(vertices);
+ free(elements);
+
+ /* 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);
+
+ 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) {
+ if (evt->button.clicks > 1)
+ nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ } else if (evt->button.button == SDL_BUTTON_MIDDLE)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else 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) {
+ /* mouse motion */
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ /* text input */
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ /* mouse wheel */
+ nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ 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/sfml_opengl2/Makefile b/nuklear/demo/sfml_opengl2/Makefile
new file mode 100644
index 0000000..28848a4
--- /dev/null
+++ b/nuklear/demo/sfml_opengl2/Makefile
@@ -0,0 +1,33 @@
+# Install
+CC = g++
+BIN = demo
+
+# Flags
+CFLAGS += -s -O2
+
+SRC = main.cpp
+OBJ = $(SRC:.cpp=.o)
+
+ifeq ($(OS),Windows_NT)
+ # Edit the line below to point to your SFML folder on Windows
+ SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML
+
+ BIN := $(BIN).exe
+ LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32
+else
+ # Edit the line below to point to your SFML folder on Linux/MacOS
+ SFML_DIR = /home/ricky/Libraries/SFML
+
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL
+ else
+ LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr
+ endif
+endif
+
+SFML_INC = -I $(SFML_DIR)/include
+SFML_LIB = -L $(SFML_DIR)/lib
+
+$(BIN):
+ $(CC) $(SRC) $(CFLAGS) -o $(BIN) $(SFML_INC) $(SFML_LIB) $(LIBS)
diff --git a/nuklear/demo/sfml_opengl2/Readme.md b/nuklear/demo/sfml_opengl2/Readme.md
new file mode 100644
index 0000000..e3879c0
--- /dev/null
+++ b/nuklear/demo/sfml_opengl2/Readme.md
@@ -0,0 +1,9 @@
+# SFML 2.4 nuklear backend
+
+This backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML.
+
+## Compiling
+
+You have to edit the Makefile provided so that you can build the demo. Edit the SFML_DIR variable to point to your SFML root folder. This will be the folder to which SFML was installed and contains the lib and include folders.
+
+On Linux there is an extra step. You need to install the the udev development files.
diff --git a/nuklear/demo/sfml_opengl2/main.cpp b/nuklear/demo/sfml_opengl2/main.cpp
new file mode 100644
index 0000000..805c1f8
--- /dev/null
+++ b/nuklear/demo/sfml_opengl2/main.cpp
@@ -0,0 +1,181 @@
+/* nuklear - v1.32.0 - 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 <SFML/OpenGL.hpp>
+#include <SFML/Window.hpp>
+
+#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_SFML_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sfml_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int main(void)
+{
+ /* Platform */
+ sf::ContextSettings settings(24, 8, 4, 2, 2);
+ sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings);
+ win.setVerticalSyncEnabled(true);
+ win.setActive(true);
+ glViewport(0, 0, win.getSize().x, win.getSize().y);
+
+ /* GUI */
+ struct nk_context *ctx;
+ ctx = nk_sfml_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_sfml_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_sfml_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/
+
+ /* style.c */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ struct nk_colorf bg;
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ while (win.isOpen())
+ {
+ /* Input */
+ sf::Event evt;
+ nk_input_begin(ctx);
+ while(win.pollEvent(evt)) {
+ if(evt.type == sf::Event::Closed)
+ win.close();
+ else if(evt.type == sf::Event::Resized)
+ glViewport(0, 0, evt.size.width, evt.size.height);
+ nk_sfml_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ win.setActive(true);
+ nk_color_fv(bg, background);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* IMPORTANT: `nk_sfml_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_sfml_render(NK_ANTI_ALIASING_ON);
+ win.display();
+ }
+ nk_sfml_shutdown();
+ return 0;
+}
+
diff --git a/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h b/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h
new file mode 100644
index 0000000..9649ec0
--- /dev/null
+++ b/nuklear/demo/sfml_opengl2/nuklear_sfml_gl2.h
@@ -0,0 +1,359 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SFML_GL2_H_
+#define NK_SFML_GL2_H_
+
+#include <SFML/Window.hpp>
+
+NK_API struct nk_context* nk_sfml_init(sf::Window* window);
+NK_API void nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
+NK_API void nk_sfml_font_stash_end(void);
+NK_API int nk_sfml_handle_event(sf::Event* event);
+NK_API void nk_sfml_render(enum nk_anti_aliasing);
+NK_API void nk_sfml_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+ #ifdef NK_SFML_GL2_IMPLEMENTATION
+
+struct nk_sfml_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+struct nk_sfml_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_sfml {
+ sf::Window* window;
+ struct nk_sfml_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sfml;
+
+NK_INTERN void
+nk_sfml_device_upload_atlas(const void* image, int width, int height)
+{
+ struct nk_sfml_device* dev = &sfml.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_sfml_render(enum nk_anti_aliasing AA)
+{
+ /* setup global state */
+ struct nk_sfml_device* dev = &sfml.ogl;
+
+ int window_width = sfml.window->getSize().x;
+ int window_height = sfml.window->getSize().y;
+
+ 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);
+
+ glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height);
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, window_width, window_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_sfml_vertex);
+ size_t vp = offsetof(struct nk_sfml_vertex, position);
+ size_t vt = offsetof(struct nk_sfml_vertex, uv);
+ size_t vc = offsetof(struct nk_sfml_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_sfml_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sfml_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_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 vertices */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&sfml.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, &sfml.ctx, &dev->cmds)
+ {
+ if(!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((window_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(&sfml.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_TEXTURE);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+static void
+nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
+{
+#if 0
+ /* Not Implemented in SFML */
+ sf::Clipboard clipboard(sfml.window);
+ const char* text = clipboard.getText();
+
+ if(text)
+ nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+#endif
+}
+
+static void
+nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
+{
+#if 0
+ 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';
+
+ /* Not Implemented in SFML */
+ sf::Clipboard clipboard(sfml.window);
+ clipboard.setText(str);
+ free(str);
+#endif
+}
+
+NK_API struct nk_context*
+nk_sfml_init(sf::Window* window)
+{
+ sfml.window = window;
+ nk_init_default(&sfml.ctx, 0);
+ sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
+ sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
+ sfml.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_buffer_init_default(&sfml.ogl.cmds);
+ return &sfml.ctx;
+}
+
+NK_API void
+nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
+{
+ nk_font_atlas_init_default(&sfml.atlas);
+ nk_font_atlas_begin(&sfml.atlas);
+ *atlas = &sfml.atlas;
+}
+
+NK_API void
+nk_sfml_font_stash_end()
+{
+ int w, h;
+ const void* img;
+ img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_sfml_device_upload_atlas(img, w, h);
+ nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
+ if(sfml.atlas.default_font)
+ nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sfml_handle_event(sf::Event* evt)
+{
+ struct nk_context* ctx = &sfml.ctx;
+ /* optional grabbing behavior */
+ if(ctx->input.mouse.grab)
+ ctx->input.mouse.grab = 0;
+ else if(ctx->input.mouse.ungrab) {
+ int x = (int)ctx->input.mouse.prev.x;
+ int y = (int)ctx->input.mouse.prev.y;
+ sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
+ ctx->input.mouse.ungrab = 0;
+ }
+ if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
+ {
+ int down = evt->type == sf::Event::KeyPressed;
+ sf::Keyboard::Key key = evt->key.code;
+ if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
+ nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if(key == sf::Keyboard::Delete)
+ nk_input_key(ctx, NK_KEY_DEL, down);
+ else if(key == sf::Keyboard::Return)
+ nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if(key == sf::Keyboard::Tab)
+ nk_input_key(ctx, NK_KEY_TAB, down);
+ else if(key == sf::Keyboard::BackSpace)
+ nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if(key == sf::Keyboard::Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if(key == sf::Keyboard::End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if(key == sf::Keyboard::PageDown)
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if(key == sf::Keyboard::PageUp)
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if(key == sf::Keyboard::Z)
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::R)
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::C)
+ nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::V)
+ nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::X)
+ nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::B)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::E)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::Up)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if(key == sf::Keyboard::Down)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if(key == sf::Keyboard::Left) {
+ if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else nk_input_key(ctx, NK_KEY_LEFT, down);
+ } else if(key == sf::Keyboard::Right) {
+ if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+ 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 == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
+ int down = evt->type == sf::Event::MouseButtonPressed;
+ const int x = evt->mouseButton.x, y = evt->mouseButton.y;
+ if(evt->mouseButton.button == sf::Mouse::Left)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if(evt->mouseButton.button == sf::Mouse::Middle)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ if(evt->mouseButton.button == sf::Mouse::Right)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else return 0;
+ return 1;
+ } else if(evt->type == sf::Event::MouseMoved) {
+ nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
+ return 1;
+ } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
+ int down = evt->type == sf::Event::TouchBegan;
+ const int x = evt->touch.x, y = evt->touch.y;
+ ctx->input.mouse.pos.x = x;
+ ctx->input.mouse.pos.y = y;
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ return 1;
+ } else if(evt->type == sf::Event::TouchMoved) {
+ if(ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x;
+ int y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
+ } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
+ return 1;
+ } else if(evt->type == sf::Event::TextEntered) {
+ nk_input_unicode(ctx, evt->text.unicode);
+ return 1;
+ } else if(evt->type == sf::Event::MouseWheelScrolled) {
+ nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sfml_shutdown(void)
+{
+ struct nk_sfml_device* dev = &sfml.ogl;
+ nk_font_atlas_clear(&sfml.atlas);
+ nk_free(&sfml.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ memset(&sfml, 0, sizeof(sfml));
+}
+
+#endif
diff --git a/nuklear/demo/sfml_opengl3/Makefile b/nuklear/demo/sfml_opengl3/Makefile
new file mode 100644
index 0000000..b30bf28
--- /dev/null
+++ b/nuklear/demo/sfml_opengl3/Makefile
@@ -0,0 +1,37 @@
+# Install
+CC = g++
+BIN = demo
+
+# Flags
+CFLAGS += -s -O2
+
+SRC = main.cpp
+OBJ = $(SRC:.cpp=.o)
+
+ifeq ($(OS),Windows_NT)
+ # Edit the line below to point to your SFML/GLAD folder on Windows
+ SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML
+ GLAD_DIR = C:/Users/Ricky/MinGW-Libs/GLAD
+
+ BIN := $(BIN).exe
+ LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32
+else
+ # Edit the line below to point to your SFML/GLAD folder on Linux/MacOS
+ SFML_DIR = /home/ricky/Libraries/SFML
+ GLAD_DIR = /home/ricky/Libraries/GLAD
+
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL
+ else
+ LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr
+ endif
+endif
+
+SFML_INC = -I $(SFML_DIR)/include
+SFML_LIB = -L $(SFML_DIR)/lib
+GLAD_INC = -I $(GLAD_DIR)/include
+GLAD_SRC = $(GLAD_DIR)/src/glad.c
+
+$(BIN):
+ $(CC) $(GLAD_SRC) $(SRC) $(CFLAGS) $(GLAD_INC) $(SFML_INC) $(SFML_LIB) $(SFML_EXT) -o $(BIN) $(LIBS)
diff --git a/nuklear/demo/sfml_opengl3/Readme.md b/nuklear/demo/sfml_opengl3/Readme.md
new file mode 100644
index 0000000..ac03e75
--- /dev/null
+++ b/nuklear/demo/sfml_opengl3/Readme.md
@@ -0,0 +1,11 @@
+# SFML 2.4 nuklear backend
+
+This backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML.
+
+## Compiling
+
+This backend uses Glad to handle OpenGL extensions. You can download the Glad files used to test this backend from [this link](http://glad.dav1d.de/#profile=compatibility&api=gl%3D3.2&api=gles1%3Dnone&api=gles2%3D3.2&api=glsc2%3Dnone&extensions=GL_3DFX_multisample&extensions=GL_3DFX_tbuffer&extensions=GL_3DFX_texture_compression_FXT1&extensions=GL_AMD_blend_minmax_factor&extensions=GL_AMD_compressed_3DC_texture&extensions=GL_AMD_compressed_ATC_texture&extensions=GL_AMD_conservative_depth&extensions=GL_AMD_debug_output&extensions=GL_AMD_depth_clamp_separate&extensions=GL_AMD_draw_buffers_blend&extensions=GL_AMD_gcn_shader&extensions=GL_AMD_gpu_shader_half_float&extensions=GL_AMD_gpu_shader_int64&extensions=GL_AMD_interleaved_elements&extensions=GL_AMD_multi_draw_indirect&extensions=GL_AMD_name_gen_delete&extensions=GL_AMD_occlusion_query_event&extensions=GL_AMD_performance_monitor&extensions=GL_AMD_pinned_memory&extensions=GL_AMD_program_binary_Z400&extensions=GL_AMD_query_buffer_object&extensions=GL_AMD_sample_positions&extensions=GL_AMD_seamless_cubemap_per_texture&extensions=GL_AMD_shader_atomic_counter_ops&extensions=GL_AMD_shader_ballot&extensions=GL_AMD_shader_explicit_vertex_parameter&extensions=GL_AMD_shader_stencil_export&extensions=GL_AMD_shader_trinary_minmax&extensions=GL_AMD_sparse_texture&extensions=GL_AMD_stencil_operation_extended&extensions=GL_AMD_texture_texture4&extensions=GL_AMD_transform_feedback3_lines_triangles&extensions=GL_AMD_transform_feedback4&extensions=GL_AMD_vertex_shader_layer&extensions=GL_AMD_vertex_shader_tessellator&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ANDROID_extension_pack_es31a&extensions=GL_ANGLE_depth_texture&extensions=GL_ANGLE_framebuffer_blit&extensions=GL_ANGLE_framebuffer_multisample&extensions=GL_ANGLE_instanced_arrays&extensions=GL_ANGLE_pack_reverse_row_order&extensions=GL_ANGLE_program_binary&extensions=GL_ANGLE_texture_compression_dxt3&extensions=GL_ANGLE_texture_compression_dxt5&extensions=GL_ANGLE_texture_usage&extensions=GL_ANGLE_translated_shader_source&extensions=GL_APPLE_aux_depth_stencil&extensions=GL_APPLE_client_storage&extensions=GL_APPLE_clip_distance&extensions=GL_APPLE_color_buffer_packed_float&extensions=GL_APPLE_copy_texture_levels&extensions=GL_APPLE_element_array&extensions=GL_APPLE_fence&extensions=GL_APPLE_float_pixels&extensions=GL_APPLE_flush_buffer_range&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_APPLE_object_purgeable&extensions=GL_APPLE_rgb_422&extensions=GL_APPLE_row_bytes&extensions=GL_APPLE_specular_vector&extensions=GL_APPLE_sync&extensions=GL_APPLE_texture_format_BGRA8888&extensions=GL_APPLE_texture_max_level&extensions=GL_APPLE_texture_packed_float&extensions=GL_APPLE_texture_range&extensions=GL_APPLE_transform_hint&extensions=GL_APPLE_vertex_array_object&extensions=GL_APPLE_vertex_array_range&extensions=GL_APPLE_vertex_program_evaluators&extensions=GL_APPLE_ycbcr_422&extensions=GL_ARB_ES2_compatibility&extensions=GL_ARB_ES3_1_compatibility&extensions=GL_ARB_ES3_2_compatibility&extensions=GL_ARB_ES3_compatibility&extensions=GL_ARB_arrays_of_arrays&extensions=GL_ARB_base_instance&extensions=GL_ARB_bindless_texture&extensions=GL_ARB_blend_func_extended&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_cl_event&extensions=GL_ARB_clear_buffer_object&extensions=GL_ARB_clear_texture&extensions=GL_ARB_clip_control&extensions=GL_ARB_color_buffer_float&extensions=GL_ARB_compatibility&extensions=GL_ARB_compressed_texture_pixel_storage&extensions=GL_ARB_compute_shader&extensions=GL_ARB_compute_variable_group_size&extensions=GL_ARB_conditional_render_inverted&extensions=GL_ARB_conservative_depth&extensions=GL_ARB_copy_buffer&extensions=GL_ARB_copy_image&extensions=GL_ARB_cull_distance&extensions=GL_ARB_debug_output&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_depth_texture&extensions=GL_ARB_derivative_control&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_draw_buffers&extensions=GL_ARB_draw_buffers_blend&extensions=GL_ARB_draw_elements_base_vertex&extensions=GL_ARB_draw_indirect&extensions=GL_ARB_draw_instanced&extensions=GL_ARB_enhanced_layouts&extensions=GL_ARB_explicit_attrib_location&extensions=GL_ARB_explicit_uniform_location&extensions=GL_ARB_fragment_coord_conventions&extensions=GL_ARB_fragment_layer_viewport&extensions=GL_ARB_fragment_program&extensions=GL_ARB_fragment_program_shadow&extensions=GL_ARB_fragment_shader&extensions=GL_ARB_fragment_shader_interlock&extensions=GL_ARB_framebuffer_no_attachments&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_framebuffer_sRGB&extensions=GL_ARB_geometry_shader4&extensions=GL_ARB_get_program_binary&extensions=GL_ARB_get_texture_sub_image&extensions=GL_ARB_gpu_shader5&extensions=GL_ARB_gpu_shader_fp64&extensions=GL_ARB_gpu_shader_int64&extensions=GL_ARB_half_float_pixel&extensions=GL_ARB_half_float_vertex&extensions=GL_ARB_imaging&extensions=GL_ARB_indirect_parameters&extensions=GL_ARB_instanced_arrays&extensions=GL_ARB_internalformat_query&extensions=GL_ARB_internalformat_query2&extensions=GL_ARB_invalidate_subdata&extensions=GL_ARB_map_buffer_alignment&extensions=GL_ARB_map_buffer_range&extensions=GL_ARB_matrix_palette&extensions=GL_ARB_multi_bind&extensions=GL_ARB_multi_draw_indirect&extensions=GL_ARB_multisample&extensions=GL_ARB_multitexture&extensions=GL_ARB_occlusion_query&extensions=GL_ARB_occlusion_query2&extensions=GL_ARB_parallel_shader_compile&extensions=GL_ARB_pipeline_statistics_query&extensions=GL_ARB_pixel_buffer_object&extensions=GL_ARB_point_parameters&extensions=GL_ARB_point_sprite&extensions=GL_ARB_post_depth_coverage&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_provoking_vertex&extensions=GL_ARB_query_buffer_object&extensions=GL_ARB_robust_buffer_access_behavior&extensions=GL_ARB_robustness&extensions=GL_ARB_robustness_isolation&extensions=GL_ARB_sample_locations&extensions=GL_ARB_sample_shading&extensions=GL_ARB_sampler_objects&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_seamless_cubemap_per_texture&extensions=GL_ARB_separate_shader_objects&extensions=GL_ARB_shader_atomic_counter_ops&extensions=GL_ARB_shader_atomic_counters&extensions=GL_ARB_shader_ballot&extensions=GL_ARB_shader_bit_encoding&extensions=GL_ARB_shader_clock&extensions=GL_ARB_shader_draw_parameters&extensions=GL_ARB_shader_group_vote&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_image_size&extensions=GL_ARB_shader_objects&extensions=GL_ARB_shader_precision&extensions=GL_ARB_shader_stencil_export&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_shader_subroutine&extensions=GL_ARB_shader_texture_image_samples&extensions=GL_ARB_shader_texture_lod&extensions=GL_ARB_shader_viewport_layer_array&extensions=GL_ARB_shading_language_100&extensions=GL_ARB_shading_language_420pack&extensions=GL_ARB_shading_language_include&extensions=GL_ARB_shading_language_packing&extensions=GL_ARB_shadow&extensions=GL_ARB_shadow_ambient&extensions=GL_ARB_sparse_buffer&extensions=GL_ARB_sparse_texture&extensions=GL_ARB_sparse_texture2&extensions=GL_ARB_sparse_texture_clamp&extensions=GL_ARB_stencil_texturing&extensions=GL_ARB_sync&extensions=GL_ARB_tessellation_shader&extensions=GL_ARB_texture_barrier&extensions=GL_ARB_texture_border_clamp&extensions=GL_ARB_texture_buffer_object&extensions=GL_ARB_texture_buffer_object_rgb32&extensions=GL_ARB_texture_buffer_range&extensions=GL_ARB_texture_compression&extensions=GL_ARB_texture_compression_bptc&extensions=GL_ARB_texture_compression_rgtc&extensions=GL_ARB_texture_cube_map&extensions=GL_ARB_texture_cube_map_array&extensions=GL_ARB_texture_env_add&extensions=GL_ARB_texture_env_combine&extensions=GL_ARB_texture_env_crossbar&extensions=GL_ARB_texture_env_dot3&extensions=GL_ARB_texture_filter_minmax&extensions=GL_ARB_texture_float&extensions=GL_ARB_texture_gather&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_texture_mirrored_repeat&extensions=GL_ARB_texture_multisample&extensions=GL_ARB_texture_non_power_of_two&extensions=GL_ARB_texture_query_levels&extensions=GL_ARB_texture_query_lod&extensions=GL_ARB_texture_rectangle&extensions=GL_ARB_texture_rg&extensions=GL_ARB_texture_rgb10_a2ui&extensions=GL_ARB_texture_stencil8&extensions=GL_ARB_texture_storage&extensions=GL_ARB_texture_storage_multisample&extensions=GL_ARB_texture_swizzle&extensions=GL_ARB_texture_view&extensions=GL_ARB_timer_query&extensions=GL_ARB_transform_feedback2&extensions=GL_ARB_transform_feedback3&extensions=GL_ARB_transform_feedback_instanced&extensions=GL_ARB_transform_feedback_overflow_query&extensions=GL_ARB_transpose_matrix&extensions=GL_ARB_uniform_buffer_object&extensions=GL_ARB_vertex_array_bgra&extensions=GL_ARB_vertex_array_object&extensions=GL_ARB_vertex_attrib_64bit&extensions=GL_ARB_vertex_attrib_binding&extensions=GL_ARB_vertex_blend&extensions=GL_ARB_vertex_buffer_object&extensions=GL_ARB_vertex_program&extensions=GL_ARB_vertex_shader&extensions=GL_ARB_vertex_type_10f_11f_11f_rev&extensions=GL_ARB_vertex_type_2_10_10_10_rev&extensions=GL_ARB_viewport_array&extensions=GL_ARB_window_pos&extensions=GL_ARM_mali_program_binary&extensions=GL_ARM_mali_shader_binary&extensions=GL_ARM_rgba8&extensions=GL_ARM_shader_framebuffer_fetch&extensions=GL_ARM_shader_framebuffer_fetch_depth_stencil&extensions=GL_ATI_draw_buffers&extensions=GL_ATI_element_array&extensions=GL_ATI_envmap_bumpmap&extensions=GL_ATI_fragment_shader&extensions=GL_ATI_map_object_buffer&extensions=GL_ATI_meminfo&extensions=GL_ATI_pixel_format_float&extensions=GL_ATI_pn_triangles&extensions=GL_ATI_separate_stencil&extensions=GL_ATI_text_fragment_shader&extensions=GL_ATI_texture_env_combine3&extensions=GL_ATI_texture_float&extensions=GL_ATI_texture_mirror_once&extensions=GL_ATI_vertex_array_object&extensions=GL_ATI_vertex_attrib_array_object&extensions=GL_ATI_vertex_streams&extensions=GL_DMP_program_binary&extensions=GL_DMP_shader_binary&extensions=GL_EXT_422_pixels&extensions=GL_EXT_YUV_target&extensions=GL_EXT_abgr&extensions=GL_EXT_base_instance&extensions=GL_EXT_bgra&extensions=GL_EXT_bindable_uniform&extensions=GL_EXT_blend_color&extensions=GL_EXT_blend_equation_separate&extensions=GL_EXT_blend_func_extended&extensions=GL_EXT_blend_func_separate&extensions=GL_EXT_blend_logic_op&extensions=GL_EXT_blend_minmax&extensions=GL_EXT_blend_subtract&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clear_texture&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_clip_volume_hint&extensions=GL_EXT_cmyka&extensions=GL_EXT_color_buffer_float&extensions=GL_EXT_color_buffer_half_float&extensions=GL_EXT_color_subtable&extensions=GL_EXT_compiled_vertex_array&extensions=GL_EXT_conservative_depth&extensions=GL_EXT_convolution&extensions=GL_EXT_coordinate_frame&extensions=GL_EXT_copy_image&extensions=GL_EXT_copy_texture&extensions=GL_EXT_cull_vertex&extensions=GL_EXT_debug_label&extensions=GL_EXT_debug_marker&extensions=GL_EXT_depth_bounds_test&extensions=GL_EXT_direct_state_access&extensions=GL_EXT_discard_framebuffer&extensions=GL_EXT_disjoint_timer_query&extensions=GL_EXT_draw_buffers&extensions=GL_EXT_draw_buffers2&extensions=GL_EXT_draw_buffers_indexed&extensions=GL_EXT_draw_elements_base_vertex&extensions=GL_EXT_draw_instanced&extensions=GL_EXT_draw_range_elements&extensions=GL_EXT_draw_transform_feedback&extensions=GL_EXT_float_blend&extensions=GL_EXT_fog_coord&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_multisample_blit_scaled&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_framebuffer_sRGB&extensions=GL_EXT_geometry_point_size&extensions=GL_EXT_geometry_shader&extensions=GL_EXT_geometry_shader4&extensions=GL_EXT_gpu_program_parameters&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_gpu_shader5&extensions=GL_EXT_histogram&extensions=GL_EXT_index_array_formats&extensions=GL_EXT_index_func&extensions=GL_EXT_index_material&extensions=GL_EXT_index_texture&extensions=GL_EXT_instanced_arrays&extensions=GL_EXT_light_texture&extensions=GL_EXT_map_buffer_range&extensions=GL_EXT_misc_attribute&extensions=GL_EXT_multi_draw_arrays&extensions=GL_EXT_multi_draw_indirect&extensions=GL_EXT_multisample&extensions=GL_EXT_multisampled_compatibility&extensions=GL_EXT_multisampled_render_to_texture&extensions=GL_EXT_multiview_draw_buffers&extensions=GL_EXT_occlusion_query_boolean&extensions=GL_EXT_packed_depth_stencil&extensions=GL_EXT_packed_float&extensions=GL_EXT_packed_pixels&extensions=GL_EXT_paletted_texture&extensions=GL_EXT_pixel_buffer_object&extensions=GL_EXT_pixel_transform&extensions=GL_EXT_pixel_transform_color_table&extensions=GL_EXT_point_parameters&extensions=GL_EXT_polygon_offset&extensions=GL_EXT_polygon_offset_clamp&extensions=GL_EXT_post_depth_coverage&extensions=GL_EXT_primitive_bounding_box&extensions=GL_EXT_protected_textures&extensions=GL_EXT_provoking_vertex&extensions=GL_EXT_pvrtc_sRGB&extensions=GL_EXT_raster_multisample&extensions=GL_EXT_read_format_bgra&extensions=GL_EXT_render_snorm&extensions=GL_EXT_rescale_normal&extensions=GL_EXT_robustness&extensions=GL_EXT_sRGB&extensions=GL_EXT_sRGB_write_control&extensions=GL_EXT_secondary_color&extensions=GL_EXT_separate_shader_objects&extensions=GL_EXT_separate_specular_color&extensions=GL_EXT_shader_framebuffer_fetch&extensions=GL_EXT_shader_group_vote&extensions=GL_EXT_shader_image_load_formatted&extensions=GL_EXT_shader_image_load_store&extensions=GL_EXT_shader_implicit_conversions&extensions=GL_EXT_shader_integer_mix&extensions=GL_EXT_shader_io_blocks&extensions=GL_EXT_shader_non_constant_global_initializers&extensions=GL_EXT_shader_pixel_local_storage&extensions=GL_EXT_shader_pixel_local_storage2&extensions=GL_EXT_shader_texture_lod&extensions=GL_EXT_shadow_funcs&extensions=GL_EXT_shadow_samplers&extensions=GL_EXT_shared_texture_palette&extensions=GL_EXT_sparse_texture&extensions=GL_EXT_sparse_texture2&extensions=GL_EXT_stencil_clear_tag&extensions=GL_EXT_stencil_two_side&extensions=GL_EXT_stencil_wrap&extensions=GL_EXT_subtexture&extensions=GL_EXT_tessellation_point_size&extensions=GL_EXT_tessellation_shader&extensions=GL_EXT_texture&extensions=GL_EXT_texture3D&extensions=GL_EXT_texture_array&extensions=GL_EXT_texture_border_clamp&extensions=GL_EXT_texture_buffer&extensions=GL_EXT_texture_buffer_object&extensions=GL_EXT_texture_compression_dxt1&extensions=GL_EXT_texture_compression_latc&extensions=GL_EXT_texture_compression_rgtc&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_cube_map&extensions=GL_EXT_texture_cube_map_array&extensions=GL_EXT_texture_env_add&extensions=GL_EXT_texture_env_combine&extensions=GL_EXT_texture_env_dot3&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_filter_minmax&extensions=GL_EXT_texture_format_BGRA8888&extensions=GL_EXT_texture_integer&extensions=GL_EXT_texture_lod_bias&extensions=GL_EXT_texture_mirror_clamp&extensions=GL_EXT_texture_norm16&extensions=GL_EXT_texture_object&extensions=GL_EXT_texture_perturb_normal&extensions=GL_EXT_texture_rg&extensions=GL_EXT_texture_sRGB&extensions=GL_EXT_texture_sRGB_R8&extensions=GL_EXT_texture_sRGB_RG8&extensions=GL_EXT_texture_sRGB_decode&extensions=GL_EXT_texture_shared_exponent&extensions=GL_EXT_texture_snorm&extensions=GL_EXT_texture_storage&extensions=GL_EXT_texture_swizzle&extensions=GL_EXT_texture_type_2_10_10_10_REV&extensions=GL_EXT_texture_view&extensions=GL_EXT_timer_query&extensions=GL_EXT_transform_feedback&extensions=GL_EXT_unpack_subimage&extensions=GL_EXT_vertex_array&extensions=GL_EXT_vertex_array_bgra&extensions=GL_EXT_vertex_attrib_64bit&extensions=GL_EXT_vertex_shader&extensions=GL_EXT_vertex_weighting&extensions=GL_EXT_window_rectangles&extensions=GL_EXT_x11_sync_object&extensions=GL_FJ_shader_binary_GCCSO&extensions=GL_GREMEDY_frame_terminator&extensions=GL_GREMEDY_string_marker&extensions=GL_HP_convolution_border_modes&extensions=GL_HP_image_transform&extensions=GL_HP_occlusion_test&extensions=GL_HP_texture_lighting&extensions=GL_IBM_cull_vertex&extensions=GL_IBM_multimode_draw_arrays&extensions=GL_IBM_rasterpos_clip&extensions=GL_IBM_static_data&extensions=GL_IBM_texture_mirrored_repeat&extensions=GL_IBM_vertex_array_lists&extensions=GL_IMG_bindless_texture&extensions=GL_IMG_framebuffer_downsample&extensions=GL_IMG_multisampled_render_to_texture&extensions=GL_IMG_program_binary&extensions=GL_IMG_read_format&extensions=GL_IMG_shader_binary&extensions=GL_IMG_texture_compression_pvrtc&extensions=GL_IMG_texture_compression_pvrtc2&extensions=GL_IMG_texture_filter_cubic&extensions=GL_INGR_blend_func_separate&extensions=GL_INGR_color_clamp&extensions=GL_INGR_interlace_read&extensions=GL_INTEL_conservative_rasterization&extensions=GL_INTEL_fragment_shader_ordering&extensions=GL_INTEL_framebuffer_CMAA&extensions=GL_INTEL_map_texture&extensions=GL_INTEL_parallel_arrays&extensions=GL_INTEL_performance_query&extensions=GL_KHR_blend_equation_advanced&extensions=GL_KHR_blend_equation_advanced_coherent&extensions=GL_KHR_context_flush_control&extensions=GL_KHR_debug&extensions=GL_KHR_no_error&extensions=GL_KHR_robust_buffer_access_behavior&extensions=GL_KHR_robustness&extensions=GL_KHR_texture_compression_astc_hdr&extensions=GL_KHR_texture_compression_astc_ldr&extensions=GL_KHR_texture_compression_astc_sliced_3d&extensions=GL_MESAX_texture_stack&extensions=GL_MESA_pack_invert&extensions=GL_MESA_resize_buffers&extensions=GL_MESA_window_pos&extensions=GL_MESA_ycbcr_texture&extensions=GL_NVX_conditional_render&extensions=GL_NVX_gpu_memory_info&extensions=GL_NV_bindless_multi_draw_indirect&extensions=GL_NV_bindless_multi_draw_indirect_count&extensions=GL_NV_bindless_texture&extensions=GL_NV_blend_equation_advanced&extensions=GL_NV_blend_equation_advanced_coherent&extensions=GL_NV_blend_square&extensions=GL_NV_clip_space_w_scaling&extensions=GL_NV_command_list&extensions=GL_NV_compute_program5&extensions=GL_NV_conditional_render&extensions=GL_NV_conservative_raster&extensions=GL_NV_conservative_raster_dilate&extensions=GL_NV_conservative_raster_pre_snap_triangles&extensions=GL_NV_copy_buffer&extensions=GL_NV_copy_depth_to_color&extensions=GL_NV_copy_image&extensions=GL_NV_coverage_sample&extensions=GL_NV_deep_texture3D&extensions=GL_NV_depth_buffer_float&extensions=GL_NV_depth_clamp&extensions=GL_NV_depth_nonlinear&extensions=GL_NV_draw_buffers&extensions=GL_NV_draw_instanced&extensions=GL_NV_draw_texture&extensions=GL_NV_evaluators&extensions=GL_NV_explicit_attrib_location&extensions=GL_NV_explicit_multisample&extensions=GL_NV_fbo_color_attachments&extensions=GL_NV_fence&extensions=GL_NV_fill_rectangle&extensions=GL_NV_float_buffer&extensions=GL_NV_fog_distance&extensions=GL_NV_fragment_coverage_to_color&extensions=GL_NV_fragment_program&extensions=GL_NV_fragment_program2&extensions=GL_NV_fragment_program4&extensions=GL_NV_fragment_program_option&extensions=GL_NV_fragment_shader_interlock&extensions=GL_NV_framebuffer_blit&extensions=GL_NV_framebuffer_mixed_samples&extensions=GL_NV_framebuffer_multisample&extensions=GL_NV_framebuffer_multisample_coverage&extensions=GL_NV_generate_mipmap_sRGB&extensions=GL_NV_geometry_program4&extensions=GL_NV_geometry_shader4&extensions=GL_NV_geometry_shader_passthrough&extensions=GL_NV_gpu_program4&extensions=GL_NV_gpu_program5&extensions=GL_NV_gpu_program5_mem_extended&extensions=GL_NV_gpu_shader5&extensions=GL_NV_half_float&extensions=GL_NV_image_formats&extensions=GL_NV_instanced_arrays&extensions=GL_NV_internalformat_sample_query&extensions=GL_NV_light_max_exponent&extensions=GL_NV_multisample_coverage&extensions=GL_NV_multisample_filter_hint&extensions=GL_NV_non_square_matrices&extensions=GL_NV_occlusion_query&extensions=GL_NV_packed_depth_stencil&extensions=GL_NV_parameter_buffer_object&extensions=GL_NV_parameter_buffer_object2&extensions=GL_NV_path_rendering&extensions=GL_NV_path_rendering_shared_edge&extensions=GL_NV_pixel_data_range&extensions=GL_NV_point_sprite&extensions=GL_NV_polygon_mode&extensions=GL_NV_present_video&extensions=GL_NV_primitive_restart&extensions=GL_NV_read_buffer&extensions=GL_NV_read_buffer_front&extensions=GL_NV_read_depth&extensions=GL_NV_read_depth_stencil&extensions=GL_NV_read_stencil&extensions=GL_NV_register_combiners&extensions=GL_NV_register_combiners2&extensions=GL_NV_robustness_video_memory_purge&extensions=GL_NV_sRGB_formats&extensions=GL_NV_sample_locations&extensions=GL_NV_sample_mask_override_coverage&extensions=GL_NV_shader_atomic_counters&extensions=GL_NV_shader_atomic_float&extensions=GL_NV_shader_atomic_float64&extensions=GL_NV_shader_atomic_fp16_vector&extensions=GL_NV_shader_atomic_int64&extensions=GL_NV_shader_buffer_load&extensions=GL_NV_shader_buffer_store&extensions=GL_NV_shader_noperspective_interpolation&extensions=GL_NV_shader_storage_buffer_object&extensions=GL_NV_shader_thread_group&extensions=GL_NV_shader_thread_shuffle&extensions=GL_NV_shadow_samplers_array&extensions=GL_NV_shadow_samplers_cube&extensions=GL_NV_stereo_view_rendering&extensions=GL_NV_tessellation_program5&extensions=GL_NV_texgen_emboss&extensions=GL_NV_texgen_reflection&extensions=GL_NV_texture_barrier&extensions=GL_NV_texture_border_clamp&extensions=GL_NV_texture_compression_s3tc_update&extensions=GL_NV_texture_compression_vtc&extensions=GL_NV_texture_env_combine4&extensions=GL_NV_texture_expand_normal&extensions=GL_NV_texture_multisample&extensions=GL_NV_texture_npot_2D_mipmap&extensions=GL_NV_texture_rectangle&extensions=GL_NV_texture_shader&extensions=GL_NV_texture_shader2&extensions=GL_NV_texture_shader3&extensions=GL_NV_transform_feedback&extensions=GL_NV_transform_feedback2&extensions=GL_NV_uniform_buffer_unified_memory&extensions=GL_NV_vdpau_interop&extensions=GL_NV_vertex_array_range&extensions=GL_NV_vertex_array_range2&extensions=GL_NV_vertex_attrib_integer_64bit&extensions=GL_NV_vertex_buffer_unified_memory&extensions=GL_NV_vertex_program&extensions=GL_NV_vertex_program1_1&extensions=GL_NV_vertex_program2&extensions=GL_NV_vertex_program2_option&extensions=GL_NV_vertex_program3&extensions=GL_NV_vertex_program4&extensions=GL_NV_video_capture&extensions=GL_NV_viewport_array&extensions=GL_NV_viewport_array2&extensions=GL_NV_viewport_swizzle&extensions=GL_OES_EGL_image&extensions=GL_OES_EGL_image_external&extensions=GL_OES_EGL_image_external_essl3&extensions=GL_OES_byte_coordinates&extensions=GL_OES_compressed_ETC1_RGB8_sub_texture&extensions=GL_OES_compressed_ETC1_RGB8_texture&extensions=GL_OES_compressed_paletted_texture&extensions=GL_OES_copy_image&extensions=GL_OES_depth24&extensions=GL_OES_depth32&extensions=GL_OES_depth_texture&extensions=GL_OES_draw_buffers_indexed&extensions=GL_OES_draw_elements_base_vertex&extensions=GL_OES_element_index_uint&extensions=GL_OES_fbo_render_mipmap&extensions=GL_OES_fixed_point&extensions=GL_OES_fragment_precision_high&extensions=GL_OES_geometry_point_size&extensions=GL_OES_geometry_shader&extensions=GL_OES_get_program_binary&extensions=GL_OES_gpu_shader5&extensions=GL_OES_mapbuffer&extensions=GL_OES_packed_depth_stencil&extensions=GL_OES_primitive_bounding_box&extensions=GL_OES_query_matrix&extensions=GL_OES_read_format&extensions=GL_OES_required_internalformat&extensions=GL_OES_rgb8_rgba8&extensions=GL_OES_sample_shading&extensions=GL_OES_sample_variables&extensions=GL_OES_shader_image_atomic&extensions=GL_OES_shader_io_blocks&extensions=GL_OES_shader_multisample_interpolation&extensions=GL_OES_single_precision&extensions=GL_OES_standard_derivatives&extensions=GL_OES_stencil1&extensions=GL_OES_stencil4&extensions=GL_OES_surfaceless_context&extensions=GL_OES_tessellation_point_size&extensions=GL_OES_tessellation_shader&extensions=GL_OES_texture_3D&extensions=GL_OES_texture_border_clamp&extensions=GL_OES_texture_buffer&extensions=GL_OES_texture_compression_astc&extensions=GL_OES_texture_cube_map_array&extensions=GL_OES_texture_float&extensions=GL_OES_texture_float_linear&extensions=GL_OES_texture_half_float&extensions=GL_OES_texture_half_float_linear&extensions=GL_OES_texture_npot&extensions=GL_OES_texture_stencil8&extensions=GL_OES_texture_storage_multisample_2d_array&extensions=GL_OES_texture_view&extensions=GL_OES_vertex_array_object&extensions=GL_OES_vertex_half_float&extensions=GL_OES_vertex_type_10_10_10_2&extensions=GL_OES_viewport_array&extensions=GL_OML_interlace&extensions=GL_OML_resample&extensions=GL_OML_subsample&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2&extensions=GL_OVR_multiview_multisampled_render_to_texture&extensions=GL_PGI_misc_hints&extensions=GL_PGI_vertex_hints&extensions=GL_QCOM_alpha_test&extensions=GL_QCOM_binning_control&extensions=GL_QCOM_driver_control&extensions=GL_QCOM_extended_get&extensions=GL_QCOM_extended_get2&extensions=GL_QCOM_perfmon_global_mode&extensions=GL_QCOM_tiled_rendering&extensions=GL_QCOM_writeonly_rendering&extensions=GL_REND_screen_coordinates&extensions=GL_S3_s3tc&extensions=GL_SGIS_detail_texture&extensions=GL_SGIS_fog_function&extensions=GL_SGIS_generate_mipmap&extensions=GL_SGIS_multisample&extensions=GL_SGIS_pixel_texture&extensions=GL_SGIS_point_line_texgen&extensions=GL_SGIS_point_parameters&extensions=GL_SGIS_sharpen_texture&extensions=GL_SGIS_texture4D&extensions=GL_SGIS_texture_border_clamp&extensions=GL_SGIS_texture_color_mask&extensions=GL_SGIS_texture_edge_clamp&extensions=GL_SGIS_texture_filter4&extensions=GL_SGIS_texture_lod&extensions=GL_SGIS_texture_select&extensions=GL_SGIX_async&extensions=GL_SGIX_async_histogram&extensions=GL_SGIX_async_pixel&extensions=GL_SGIX_blend_alpha_minmax&extensions=GL_SGIX_calligraphic_fragment&extensions=GL_SGIX_clipmap&extensions=GL_SGIX_convolution_accuracy&extensions=GL_SGIX_depth_pass_instrument&extensions=GL_SGIX_depth_texture&extensions=GL_SGIX_flush_raster&extensions=GL_SGIX_fog_offset&extensions=GL_SGIX_fragment_lighting&extensions=GL_SGIX_framezoom&extensions=GL_SGIX_igloo_interface&extensions=GL_SGIX_instruments&extensions=GL_SGIX_interlace&extensions=GL_SGIX_ir_instrument1&extensions=GL_SGIX_list_priority&extensions=GL_SGIX_pixel_texture&extensions=GL_SGIX_pixel_tiles&extensions=GL_SGIX_polynomial_ffd&extensions=GL_SGIX_reference_plane&extensions=GL_SGIX_resample&extensions=GL_SGIX_scalebias_hint&extensions=GL_SGIX_shadow&extensions=GL_SGIX_shadow_ambient&extensions=GL_SGIX_sprite&extensions=GL_SGIX_subsample&extensions=GL_SGIX_tag_sample_buffer&extensions=GL_SGIX_texture_add_env&extensions=GL_SGIX_texture_coordinate_clamp&extensions=GL_SGIX_texture_lod_bias&extensions=GL_SGIX_texture_multi_buffer&extensions=GL_SGIX_texture_scale_bias&extensions=GL_SGIX_vertex_preclip&extensions=GL_SGIX_ycrcb&extensions=GL_SGIX_ycrcb_subsample&extensions=GL_SGIX_ycrcba&extensions=GL_SGI_color_matrix&extensions=GL_SGI_color_table&extensions=GL_SGI_texture_color_table&extensions=GL_SUNX_constant_data&extensions=GL_SUN_convolution_border_modes&extensions=GL_SUN_global_alpha&extensions=GL_SUN_mesh_array&extensions=GL_SUN_slice_accum&extensions=GL_SUN_triangle_list&extensions=GL_SUN_vertex&extensions=GL_VIV_shader_binary&extensions=GL_WIN_phong_shading&extensions=GL_WIN_specular_fog&language=c&specification=gl&loader=on) or you can create your own loader by visiting the [Glad site](http://glad.dav1d.de/).
+
+Once SFML and Glad have been installed on your system you have to edit the Makefile provided so that you can build the demo. There are two variables that need to be edited: SFML_DIR and GLAD_DIR. Make these point to your SFML root folder and Glad root folder respectively.
+
+On Linux there is an extra step. You need to install the the udev development files.
diff --git a/nuklear/demo/sfml_opengl3/main.cpp b/nuklear/demo/sfml_opengl3/main.cpp
new file mode 100644
index 0000000..5dc2a6e
--- /dev/null
+++ b/nuklear/demo/sfml_opengl3/main.cpp
@@ -0,0 +1,189 @@
+/* nuklear - v1.32.0 - 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 <SFML/Window.hpp>
+
+#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_SFML_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sfml_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int main(void)
+{
+ /* Platform */
+ sf::ContextSettings settings(24, 8, 4, 3, 3);
+ sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings);
+ win.setVerticalSyncEnabled(true);
+ win.setActive(true);
+ if(!gladLoadGL()) { /* Load OpenGL extensions */
+ printf("Failed to load OpenGL extensions!\n");
+ return -1;
+ }
+ glViewport(0, 0, win.getSize().x, win.getSize().y);
+
+ /* GUI */
+ struct nk_context *ctx;
+ ctx = nk_sfml_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_sfml_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_sfml_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/
+
+ /* style.c */
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ struct nk_colorf bg;
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ while (win.isOpen())
+ {
+ /* Input */
+ sf::Event evt;
+ nk_input_begin(ctx);
+ while(win.pollEvent(evt)) {
+ if(evt.type == sf::Event::Closed)
+ win.close();
+ else if(evt.type == sf::Event::Resized)
+ glViewport(0, 0, evt.size.width, evt.size.height);
+
+ nk_sfml_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ float bg[4];
+ win.setActive(true);
+ nk_color_fv(bg, background);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* IMPORTANT: `nk_sfml_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_sfml_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ win.display();
+ }
+ nk_sfml_shutdown();
+ return 0;
+}
+
diff --git a/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h b/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h
new file mode 100644
index 0000000..40b390e
--- /dev/null
+++ b/nuklear/demo/sfml_opengl3/nuklear_sfml_gl3.h
@@ -0,0 +1,463 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SFML_GL3_H_
+#define NK_SFML_GL3_H_
+
+/* Feel free to edit here and include your own extension wrangler */
+#include <glad/glad.h>
+/* I use GLAD but you can use GLEW or what you like */
+
+#include <SFML/Window.hpp>
+
+NK_API struct nk_context* nk_sfml_init(sf::Window* window);
+NK_API void nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
+NK_API void nk_sfml_font_stash_end(void);
+NK_API int nk_sfml_handle_event(sf::Event* event);
+NK_API void nk_sfml_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_sfml_shutdown(void);
+
+NK_API void nk_sfml_device_create(void);
+NK_API void nk_sfml_device_destroy(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+ #ifdef NK_SFML_GL3_IMPLEMENTATION
+
+#include <string>
+
+struct nk_sfml_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_sfml_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+static struct nk_sfml {
+ sf::Window* window;
+ struct nk_sfml_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sfml;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+NK_API void
+nk_sfml_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_sfml_device* dev = &sfml.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_sfml_vertex);
+ size_t vp = offsetof(struct nk_sfml_vertex, position);
+ size_t vt = offsetof(struct nk_sfml_vertex, uv);
+ size_t vc = offsetof(struct nk_sfml_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_API void
+nk_sfml_device_destroy(void)
+{
+ struct nk_sfml_device* dev = &sfml.ogl;
+
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+NK_INTERN void
+nk_sfml_device_upload_atlas(const void* image, int width, int height)
+{
+ struct nk_sfml_device* dev = &sfml.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_sfml_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_sfml_device* dev = &sfml.ogl;
+ int window_width = sfml.window->getSize().x;
+ int window_height = sfml.window->getSize().y;
+ 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)window_width;
+ ortho[1][1] /= (GLfloat)window_height;
+
+ glViewport(0, 0, window_width, window_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_sfml_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sfml_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_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(&sfml.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, &sfml.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((window_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(&sfml.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_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
+{
+#if 0
+ /* Not Implemented in SFML */
+ (void)usr;
+ sf::Clipboard clipboard(sfml.window);
+ const char* text = clipboard.getText();
+ if(text) nk_textedit_paste(edit, text, nk_strlen(text));
+#endif
+}
+static void
+nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
+{
+#if 0
+ 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';
+
+ /* Not Implemented in SFML */
+ sf::Clipboard clipboard(sfml.window);
+ clipboard.setText(str);
+ free(str);
+#endif
+}
+
+NK_API struct nk_context*
+nk_sfml_init(sf::Window* window)
+{
+ sfml.window = window;
+ nk_init_default(&sfml.ctx, 0);
+ sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
+ sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
+ sfml.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_sfml_device_create();
+ return &sfml.ctx;
+}
+
+NK_API void
+nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
+{
+ nk_font_atlas_init_default(&sfml.atlas);
+ nk_font_atlas_begin(&sfml.atlas);
+ *atlas = &sfml.atlas;
+}
+
+NK_API void
+nk_sfml_font_stash_end()
+{
+ const void* image;
+ int w, h;
+ image = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_sfml_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
+ if(sfml.atlas.default_font)
+ nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sfml_handle_event(sf::Event* evt)
+{
+ struct nk_context* ctx = &sfml.ctx;
+ /* optional grabbing behavior */
+ if(ctx->input.mouse.grab)
+ ctx->input.mouse.grab = 0;
+ else if(ctx->input.mouse.ungrab) {
+ int x = (int)ctx->input.mouse.prev.x;
+ int y = (int)ctx->input.mouse.prev.y;
+ sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
+ ctx->input.mouse.ungrab = 0;
+ }
+ if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
+ {
+ int down = evt->type == sf::Event::KeyPressed;
+ sf::Keyboard::Key key = evt->key.code;
+ if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
+ nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if(key == sf::Keyboard::Delete)
+ nk_input_key(ctx, NK_KEY_DEL, down);
+ else if(key == sf::Keyboard::Return)
+ nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if(key == sf::Keyboard::Tab)
+ nk_input_key(ctx, NK_KEY_TAB, down);
+ else if(key == sf::Keyboard::BackSpace)
+ nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if(key == sf::Keyboard::Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if(key == sf::Keyboard::End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if(key == sf::Keyboard::PageDown)
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if(key == sf::Keyboard::PageUp)
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if(key == sf::Keyboard::Z)
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::R)
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::C)
+ nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::V)
+ nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::X)
+ nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::B)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::E)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+ else if(key == sf::Keyboard::Up)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if(key == sf::Keyboard::Down)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if(key == sf::Keyboard::Left) {
+ if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else nk_input_key(ctx, NK_KEY_LEFT, down);
+ } else if(key == sf::Keyboard::Right) {
+ if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+ 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 == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
+ int down = evt->type == sf::Event::MouseButtonPressed;
+ const int x = evt->mouseButton.x, y = evt->mouseButton.y;
+ if(evt->mouseButton.button == sf::Mouse::Left)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if(evt->mouseButton.button == sf::Mouse::Middle)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ if(evt->mouseButton.button == sf::Mouse::Right)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else return 0;
+ return 1;
+ } else if(evt->type == sf::Event::MouseMoved) {
+ nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
+ return 1;
+ } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
+ int down = evt->type == sf::Event::TouchBegan;
+ const int x = evt->touch.x, y = evt->touch.y;
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ return 1;
+ } else if(evt->type == sf::Event::TouchMoved) {
+ if(ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x;
+ int y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
+ } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
+ return 1;
+ } else if(evt->type == sf::Event::TextEntered) {
+ nk_input_unicode(ctx, evt->text.unicode);
+ return 1;
+ } else if(evt->type == sf::Event::MouseWheelScrolled) {
+ nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sfml_shutdown()
+{
+ nk_font_atlas_clear(&sfml.atlas);
+ nk_free(&sfml.ctx);
+ nk_sfml_device_destroy();
+ memset(&sfml, 0, sizeof(sfml));
+}
+
+#endif
diff --git a/nuklear/demo/style.c b/nuklear/demo/style.c
new file mode 100644
index 0000000..17c48fe
--- /dev/null
+++ b/nuklear/demo/style.c
@@ -0,0 +1,132 @@
+enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK};
+
+static void
+set_style(struct nk_context *ctx, enum theme theme)
+{
+ struct nk_color table[NK_COLOR_COUNT];
+ if (theme == THEME_WHITE) {
+ table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);
+ table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);
+ table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);
+ table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);
+ table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);
+ table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);
+ table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);
+ table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);
+ table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);
+ table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);
+ table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
+ table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);
+ 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..9057c7b
--- /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..791653d
--- /dev/null
+++ b/nuklear/demo/x11/main.c
@@ -0,0 +1,224 @@
+/* nuklear - v1.32.0 - 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
+
+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;
+ Atom wm_delete_window;
+};
+
+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 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 defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * 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);
+ xw.wm_delete_window = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(xw.dpy, xw.win, &xw.wm_delete_window, 1);
+ 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);
+
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ started = timestamp();
+ nk_input_begin(ctx);
+ while (XPending(xw.dpy)) {
+ XNextEvent(xw.dpy, &evt);
+ if (evt.type == ClientMessage) goto cleanup;
+ 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_hidden(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* 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);
+ }
+
+cleanup:
+ 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..8b6b4ff
--- /dev/null
+++ b/nuklear/demo/x11/nuklear_xlib.h
@@ -0,0 +1,957 @@
+/*
+ * Nuklear - v1.40.8 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2017 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_H_
+#define NK_XLIB_H_
+
+#include <X11/Xlib.h>
+
+typedef struct XFont XFont;
+NK_API struct nk_context* nk_xlib_init(XFont*, Display*, int scrn, Window root, unsigned w, unsigned h);
+NK_API int nk_xlib_handle_event(Display*, int scrn, Window, XEvent*);
+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*);
+NK_API void nk_xlib_push_font(XFont*);
+NK_API void nk_xlib_paste(nk_handle, struct nk_text_edit*);
+NK_API void nk_xlib_copy(nk_handle, const char*, int len);
+
+/* Image */
+#ifdef NK_XLIB_INCLUDE_STB_IMAGE
+NK_API struct nk_image nk_xsurf_load_image_from_file(char const *filename);
+NK_API struct nk_image nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize);
+#endif
+
+/* Font */
+NK_API XFont* nk_xfont_create(Display *dpy, const char *name);
+NK_API void nk_xfont_del(Display *dpy, XFont *font);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_IMPLEMENTATION
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+#include <X11/Xatom.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+
+#ifdef NK_XLIB_IMPLEMENT_STB_IMAGE
+#define STB_IMAGE_IMPLEMENTATION
+#endif
+
+#ifdef NK_XLIB_INCLUDE_STB_IMAGE
+#include "../../example/stb_image.h"
+#endif
+
+
+#ifndef NK_X11_DOUBLE_CLICK_LO
+#define NK_X11_DOUBLE_CLICK_LO 20
+#endif
+#ifndef NK_X11_DOUBLE_CLICK_HI
+#define NK_X11_DOUBLE_CLICK_HI 200
+#endif
+
+typedef struct XSurface XSurface;
+typedef struct XImageWithAlpha XImageWithAlpha;
+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;
+};
+struct XImageWithAlpha {
+ XImage* ximage;
+ GC clipMaskGC;
+ Pixmap clipMask;
+};
+static struct {
+ char *clipboard_data;
+ int clipboard_len;
+ struct nk_text_edit* clipboard_target;
+
+ Atom xa_clipboard;
+ Atom xa_targets;
+ Atom xa_text;
+ Atom xa_utf8_string;
+
+ struct nk_context ctx;
+ struct XSurface *surf;
+ Cursor cursor;
+ Display *dpy;
+ Window root;
+ long last_button_click;
+} xlib;
+
+NK_INTERN long
+nk_timestamp(void)
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) return 0;
+ return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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;
+}
+
+NK_INTERN 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));
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);return;}
+
+ {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);
+}
+
+NK_INTERN 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); return;}
+
+ {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);}
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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)
+{
+ 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);
+}
+
+NK_INTERN void
+nk_xsurf_fill_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
+ struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 128
+ 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
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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 = NK_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);
+}
+
+NK_INTERN 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);
+}
+
+
+#ifdef NK_XLIB_INCLUDE_STB_IMAGE
+NK_INTERN struct nk_image
+nk_stbi_image_to_xsurf(unsigned char *data, int width, int height, int channels) {
+ XSurface *surf = xlib.surf;
+ struct nk_image img;
+ int bpl = channels;
+ long i, isize = width*height*channels;
+ XImageWithAlpha *aimage = (XImageWithAlpha*)calloc( 1, sizeof(XImageWithAlpha) );
+ int depth = DefaultDepth(surf->dpy, surf->screen);
+ if (data == NULL) return nk_image_id(0);
+ if (aimage == NULL) return nk_image_id(0);
+
+ switch (depth){
+ case 24:
+ bpl = 4;
+ break;
+ case 16:
+ case 15:
+ bpl = 2;
+ break;
+ default:
+ bpl = 1;
+ break;
+ }
+
+ /* rgba to bgra */
+ if (channels >= 3){
+ for (i=0; i < isize; i += channels) {
+ unsigned char red = data[i+2];
+ unsigned char blue = data[i];
+ data[i] = red;
+ data[i+2] = blue;
+ }
+ }
+
+ if (channels == 4){
+ const unsigned alpha_treshold = 127;
+ aimage->clipMask = XCreatePixmap(surf->dpy, surf->drawable, width, height, 1);
+
+ if( aimage->clipMask ){
+ aimage->clipMaskGC = XCreateGC(surf->dpy, aimage->clipMask, 0, 0);
+ XSetForeground(surf->dpy, aimage->clipMaskGC, BlackPixel(surf->dpy, surf->screen));
+ XFillRectangle(surf->dpy, aimage->clipMask, aimage->clipMaskGC, 0, 0, width, height);
+
+ XSetForeground(surf->dpy, aimage->clipMaskGC, WhitePixel(surf->dpy, surf->screen));
+ for (i=0; i < isize; i += channels){
+ unsigned char alpha = data[i+3];
+ int div = i / channels;
+ int x = div % width;
+ int y = div / width;
+ if( alpha > alpha_treshold )
+ XDrawPoint(surf->dpy, aimage->clipMask, aimage->clipMaskGC, x, y);
+ }
+ }
+ }
+
+ aimage->ximage = XCreateImage(surf->dpy,
+ CopyFromParent, depth,
+ ZPixmap, 0,
+ (char*)data,
+ width, height,
+ bpl*8, bpl * width);
+ img = nk_image_ptr( (void*)aimage);
+ img.h = height;
+ img.w = width;
+ return img;
+}
+
+NK_API struct nk_image
+nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize)
+{
+ int x,y,n;
+ unsigned char *data;
+ data = stbi_load_from_memory(membuf, membufSize, &x, &y, &n, 0);
+ return nk_stbi_image_to_xsurf(data, x, y, n);
+}
+
+NK_API struct nk_image
+nk_xsurf_load_image_from_file(char const *filename)
+{
+ int x,y,n;
+ unsigned char *data;
+ data = stbi_load(filename, &x, &y, &n, 0);
+ return nk_stbi_image_to_xsurf(data, x, y, n);
+}
+#endif /* NK_XLIB_INCLUDE_STB_IMAGE */
+
+NK_INTERN void
+nk_xsurf_draw_image(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
+ struct nk_image img, struct nk_color col)
+{
+ XImageWithAlpha *aimage = img.handle.ptr;
+ if (aimage){
+ if (aimage->clipMask){
+ XSetClipMask(surf->dpy, surf->gc, aimage->clipMask);
+ XSetClipOrigin(surf->dpy, surf->gc, x, y);
+ }
+ XPutImage(surf->dpy, surf->drawable, surf->gc, aimage->ximage, 0, 0, x, y, w, h);
+ XSetClipMask(surf->dpy, surf->gc, None);
+ }
+}
+
+void
+nk_xsurf_image_free(struct nk_image* image)
+{
+ XSurface *surf = xlib.surf;
+ XImageWithAlpha *aimage = image->handle.ptr;
+ if (!aimage) return;
+ XDestroyImage(aimage->ximage);
+ XFreePixmap(surf->dpy, aimage->clipMask);
+ XFreeGC(surf->dpy, aimage->clipMaskGC);
+ free(aimage);
+}
+
+
+NK_INTERN 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);
+}
+
+NK_INTERN 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);
+}
+
+NK_INTERN void
+nk_xsurf_del(XSurface *surf)
+{
+ XFreePixmap(surf->dpy, surf->drawable);
+ XFreeGC(surf->dpy, surf->gc);
+ free(surf);
+}
+
+NK_API 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 = NK_MAX(font->ascent, (*xfonts)->ascent);
+ font->descent = NK_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;
+}
+
+NK_INTERN 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;
+ }
+}
+
+NK_API 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;
+
+ xlib.xa_clipboard = XInternAtom(dpy, "CLIPBOARD", False);
+ xlib.xa_targets = XInternAtom(dpy, "TARGETS", False);
+ xlib.xa_text = XInternAtom(dpy, "TEXT", False);
+ xlib.xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
+
+ /* 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 void
+nk_xlib_push_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_push_font(&xlib.ctx, font);
+}
+
+NK_API void
+nk_xlib_paste(nk_handle handle, struct nk_text_edit* edit)
+{
+ NK_UNUSED(handle);
+ /* Paste in X is asynchronous, so can not use a temporary text edit */
+ NK_ASSERT(edit != &xlib.ctx.text_edit && "Paste not supported for temporary editors");
+ xlib.clipboard_target = edit;
+ /* Request the contents of the primary buffer */
+ XConvertSelection(xlib.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xlib.root, CurrentTime);
+}
+
+NK_API void
+nk_xlib_copy(nk_handle handle, const char* str, int len)
+{
+ NK_UNUSED(handle);
+ free(xlib.clipboard_data);
+ xlib.clipboard_len = 0;
+ xlib.clipboard_data = malloc((size_t)len);
+ if (xlib.clipboard_data) {
+ memcpy(xlib.clipboard_data, str, (size_t)len);
+ xlib.clipboard_len = len;
+ XSetSelectionOwner(xlib.dpy, XA_PRIMARY, xlib.root, CurrentTime);
+ XSetSelectionOwner(xlib.dpy, xlib.xa_clipboard, xlib.root, CurrentTime);
+ }
+}
+
+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) {
+ if (down) { /* Double-Click Button handler */
+ long dt = nk_timestamp() - xlib.last_button_click;
+ if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
+ nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
+ xlib.last_button_click = nk_timestamp();
+ } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ } else 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, nk_vec2(0, 1.0f));
+ else if (evt->xbutton.button == Button5)
+ nk_input_scroll(ctx, nk_vec2(0, -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;
+ } else if (evt->type == SelectionClear) {
+ free(xlib.clipboard_data);
+ xlib.clipboard_data = NULL;
+ xlib.clipboard_len = 0;
+ return 1;
+ } else if (evt->type == SelectionRequest) {
+ XEvent reply;
+ reply.xselection.type = SelectionNotify;
+ reply.xselection.requestor = evt->xselectionrequest.requestor;
+ reply.xselection.selection = evt->xselectionrequest.selection;
+ reply.xselection.target = evt->xselectionrequest.target;
+ reply.xselection.property = None; /* Default refuse */
+ reply.xselection.time = evt->xselectionrequest.time;
+
+ if (reply.xselection.target == xlib.xa_targets) {
+ Atom target_list[4];
+ target_list[0] = xlib.xa_targets;
+ target_list[1] = xlib.xa_text;
+ target_list[2] = xlib.xa_utf8_string;
+ target_list[3] = XA_STRING;
+
+ reply.xselection.property = evt->xselectionrequest.property;
+ XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,
+ reply.xselection.property, XA_ATOM, 32, PropModeReplace,
+ (unsigned char*)&target_list, 4);
+ } else if (xlib.clipboard_data && (reply.xselection.target == xlib.xa_text ||
+ reply.xselection.target == xlib.xa_utf8_string || reply.xselection.target == XA_STRING)) {
+ reply.xselection.property = evt->xselectionrequest.property;
+ XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,
+ reply.xselection.property, reply.xselection.target, 8, PropModeReplace,
+ (unsigned char*)xlib.clipboard_data, xlib.clipboard_len);
+ }
+ XSendEvent(evt->xselection.display, evt->xselectionrequest.requestor, True, 0, &reply);
+ XFlush(evt->xselection.display);
+ return 1;
+ } else if (evt->type == SelectionNotify && xlib.clipboard_target) {
+ if ((evt->xselection.target != XA_STRING) &&
+ (evt->xselection.target != xlib.xa_utf8_string) &&
+ (evt->xselection.target != xlib.xa_text))
+ return 1;
+
+ {Atom actual_type;
+ int actual_format;
+ unsigned long pos = 0, len, remain;
+ unsigned char* data = 0;
+ do {
+ XGetWindowProperty(dpy, win, XA_PRIMARY, (int)pos, 1024, False,
+ AnyPropertyType, &actual_type, &actual_format, &len, &remain, &data);
+ if (len && data)
+ nk_textedit_text(xlib.clipboard_target, (char*)data, (int)len);
+ if (data != 0) XFree(data);
+ pos += (len * (unsigned long)actual_format) / 32;
+ } while (remain != 0);}
+ 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, NK_MAX(r->w -r->line_thickness, 0),
+ NK_MAX(r->h - r->line_thickness, 0), (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_IMAGE: {
+ const struct nk_command_image *i = (const struct nk_command_image *)cmd;
+ nk_xsurf_draw_image(surf, i->x, i->y, i->w, i->h, i->img, i->col);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_ARC:
+ case NK_COMMAND_ARC_FILLED:
+ case NK_COMMAND_CUSTOM:
+ 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..a3d6d32
--- /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..12cbed1
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/main.c
@@ -0,0 +1,345 @@
+/* nuklear - v1.32.0 - 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
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+ #define INCLUDE_STYLE
+ #define INCLUDE_CALCULATOR
+ #define INCLUDE_OVERVIEW
+ #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+ #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+ #include "../calculator.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+ #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+ #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+struct XWindow {
+ Display *dpy;
+ Window win;
+ XVisualInfo *vis;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XWindowAttributes attr;
+ GLXFBConfig fbc;
+ Atom wm_delete_window;
+ int width, height;
+};
+static int gl_err = nk_false;
+static int gl_error_handler(Display *dpy, XErrorEvent *ev)
+{NK_UNUSED(dpy); NK_UNUSED(ev); gl_err = nk_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 nk_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 nk_true;
+ }
+ start = term;
+ }
+ return nk_false;
+}
+
+int main(void)
+{
+ /* Platform */
+ int running = 1;
+ struct XWindow win;
+ GLXContext glContext;
+ struct nk_context *ctx;
+ struct nk_colorf bg;
+
+ 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);
+ win.wm_delete_window = XInternAtom(win.dpy, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(win.dpy, win.win, &win.wm_delete_window, 1);
+ }
+ {
+ /* 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 = nk_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, 2,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 2,
+ 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 = nk_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);*/}
+
+ #ifdef INCLUDE_STYLE
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+ #endif
+
+ bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ nk_input_begin(ctx);
+ while (XPending(win.dpy)) {
+ XNextEvent(win.dpy, &evt);
+ if (evt.type == ClientMessage) goto cleanup;
+ 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, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ bg = nk_color_picker(ctx, bg, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+ bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+ bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+ bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ #ifdef INCLUDE_CALCULATOR
+ calculator(ctx);
+ #endif
+ #ifdef INCLUDE_OVERVIEW
+ overview(ctx);
+ #endif
+ #ifdef INCLUDE_NODE_EDITOR
+ node_editor(ctx);
+ #endif
+ /* ----------------------------------------- */
+
+ /* Draw */
+ XGetWindowAttributes(win.dpy, win.win, &win.attr);
+ glViewport(0, 0, win.width, win.height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg.r, bg.g, bg.b, bg.a);
+ /* 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);
+ }
+
+cleanup:
+ 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..ab36eb6
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h
@@ -0,0 +1,376 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_GL2_H_
+#define NK_XLIB_GL2_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 <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#include <GL/gl.h>
+
+#ifndef NK_X11_DOUBLE_CLICK_LO
+#define NK_X11_DOUBLE_CLICK_LO 20
+#endif
+#ifndef NK_X11_DOUBLE_CLICK_HI
+#define NK_X11_DOUBLE_CLICK_HI 200
+#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;
+ long last_button_click;
+} x11;
+
+NK_INTERN long
+nk_timestamp(void)
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) return 0;
+ return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
+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[] = {