aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml75
-rw-r--r--CMakeLists.txt156
-rw-r--r--README.md43
-rw-r--r--VERSION1
-rw-r--r--atom_inspector.c231
-rw-r--r--atom_inspector_nk.c363
-rw-r--r--cmake/arm-linux-gnueabihf.cmake22
-rw-r--r--cmake/i686-linux-gnu.cmake11
-rw-r--r--cmake/i686-w64-mingw32.cmake25
-rw-r--r--cmake/universal-apple-darwin.cmake24
-rw-r--r--cmake/x86_64-linux-gnu.cmake8
-rw-r--r--cmake/x86_64-w64-mingw32.cmake25
-rw-r--r--encoder.h37
-rw-r--r--encoder.l205
-rw-r--r--manifest.ttl.in62
-rw-r--r--midi_inspector.c250
-rw-r--r--midi_inspector_nk.c507
-rw-r--r--nk_pugl/COPYING201
-rw-r--r--nk_pugl/nk_pugl.h (renamed from nk_pugl.h)0
-rw-r--r--nuklear/.gitattributes3
-rw-r--r--nuklear/.gitignore2
-rw-r--r--nuklear/.travis.yml16
-rw-r--r--nuklear/CHANGELOG.md190
-rw-r--r--nuklear/Readme.md111
-rw-r--r--nuklear/demo/calculator.c64
-rw-r--r--nuklear/demo/d3d11/build.bat9
-rw-r--r--nuklear/demo/d3d11/main.c278
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11.h617
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11.hlsl36
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h179
-rw-r--r--nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h350
-rw-r--r--nuklear/demo/gdi/build.bat6
-rw-r--r--nuklear/demo/gdi/main.c161
-rw-r--r--nuklear/demo/gdi/nuklear_gdi.h761
-rw-r--r--nuklear/demo/gdip/build.bat5
-rw-r--r--nuklear/demo/gdip/main.c155
-rw-r--r--nuklear/demo/gdip/nuklear_gdip.h1006
-rw-r--r--nuklear/demo/glfw_opengl2/Makefile25
-rw-r--r--nuklear/demo/glfw_opengl2/main.c165
-rw-r--r--nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h350
-rw-r--r--nuklear/demo/glfw_opengl3/Makefile25
-rw-r--r--nuklear/demo/glfw_opengl3/main.c180
-rw-r--r--nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h456
-rw-r--r--nuklear/demo/node_editor.c343
-rw-r--r--nuklear/demo/overview.c1188
-rw-r--r--nuklear/demo/sdl_opengl2/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl2/main.c181
-rw-r--r--nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h342
-rw-r--r--nuklear/demo/sdl_opengl3/Makefile25
-rw-r--r--nuklear/demo/sdl_opengl3/main.c195
-rw-r--r--nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h437
-rw-r--r--nuklear/demo/style.c132
-rw-r--r--nuklear/demo/x11/Makefile13
-rw-r--r--nuklear/demo/x11/main.c203
-rw-r--r--nuklear/demo/x11/nuklear_xlib.h693
-rw-r--r--nuklear/demo/x11_opengl2/Makefile26
-rw-r--r--nuklear/demo/x11_opengl2/main.c320
-rw-r--r--nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h357
-rw-r--r--nuklear/demo/x11_opengl3/Makefile26
-rw-r--r--nuklear/demo/x11_opengl3/main.c317
-rw-r--r--nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h725
-rw-r--r--nuklear/example/Makefile41
-rw-r--r--nuklear/example/canvas.c489
-rw-r--r--nuklear/example/extended.c906
-rw-r--r--nuklear/example/file_browser.c910
-rw-r--r--nuklear/example/icon/checked.pngbin0 -> 1813 bytes
-rw-r--r--nuklear/example/icon/cloud.pngbin0 -> 7509 bytes
-rw-r--r--nuklear/example/icon/computer.pngbin0 -> 620 bytes
-rw-r--r--nuklear/example/icon/copy.pngbin0 -> 655 bytes
-rw-r--r--nuklear/example/icon/default.pngbin0 -> 460 bytes
-rw-r--r--nuklear/example/icon/delete.pngbin0 -> 11040 bytes
-rw-r--r--nuklear/example/icon/desktop.pngbin0 -> 583 bytes
-rw-r--r--nuklear/example/icon/directory.pngbin0 -> 533 bytes
-rw-r--r--nuklear/example/icon/edit.pngbin0 -> 14998 bytes
-rw-r--r--nuklear/example/icon/export.pngbin0 -> 13336 bytes
-rw-r--r--nuklear/example/icon/font.pngbin0 -> 561 bytes
-rw-r--r--nuklear/example/icon/home.pngbin0 -> 819 bytes
-rw-r--r--nuklear/example/icon/img.pngbin0 -> 648 bytes
-rw-r--r--nuklear/example/icon/movie.pngbin0 -> 626 bytes
-rw-r--r--nuklear/example/icon/music.pngbin0 -> 610 bytes
-rw-r--r--nuklear/example/icon/next.pngbin0 -> 703 bytes
-rw-r--r--nuklear/example/icon/pause.pngbin0 -> 1338 bytes
-rw-r--r--nuklear/example/icon/pen.pngbin0 -> 5949 bytes
-rw-r--r--nuklear/example/icon/phone.pngbin0 -> 15778 bytes
-rw-r--r--nuklear/example/icon/plane.pngbin0 -> 13546 bytes
-rw-r--r--nuklear/example/icon/play.pngbin0 -> 566 bytes
-rw-r--r--nuklear/example/icon/prev.pngbin0 -> 701 bytes
-rw-r--r--nuklear/example/icon/rocket.pngbin0 -> 1121 bytes
-rw-r--r--nuklear/example/icon/settings.pngbin0 -> 15671 bytes
-rw-r--r--nuklear/example/icon/stop.pngbin0 -> 520 bytes
-rw-r--r--nuklear/example/icon/text.pngbin0 -> 601 bytes
-rw-r--r--nuklear/example/icon/tools.pngbin0 -> 24483 bytes
-rw-r--r--nuklear/example/icon/unchecked.pngbin0 -> 1044 bytes
-rw-r--r--nuklear/example/icon/volume.pngbin0 -> 25438 bytes
-rw-r--r--nuklear/example/icon/wifi.pngbin0 -> 18857 bytes
-rw-r--r--nuklear/example/images/image1.pngbin0 -> 42882 bytes
-rw-r--r--nuklear/example/images/image2.pngbin0 -> 5671 bytes
-rw-r--r--nuklear/example/images/image3.pngbin0 -> 131502 bytes
-rw-r--r--nuklear/example/images/image4.pngbin0 -> 185821 bytes
-rw-r--r--nuklear/example/images/image5.pngbin0 -> 98475 bytes
-rw-r--r--nuklear/example/images/image6.pngbin0 -> 35633 bytes
-rw-r--r--nuklear/example/images/image7.pngbin0 -> 13960 bytes
-rw-r--r--nuklear/example/images/image8.pngbin0 -> 45987 bytes
-rw-r--r--nuklear/example/images/image9.pngbin0 -> 30759 bytes
-rw-r--r--nuklear/example/skinning.c825
-rw-r--r--nuklear/example/skins/gwen.pngbin0 -> 24565 bytes
-rw-r--r--nuklear/example/stb_image.h6509
-rw-r--r--nuklear/extra_font/Cousine-Regular.ttfbin0 -> 43912 bytes
-rw-r--r--nuklear/extra_font/DroidSans.ttfbin0 -> 190044 bytes
-rw-r--r--nuklear/extra_font/Karla-Regular.ttfbin0 -> 16848 bytes
-rw-r--r--nuklear/extra_font/ProggyClean.ttfbin0 -> 41208 bytes
-rw-r--r--nuklear/extra_font/ProggyTiny.ttfbin0 -> 35656 bytes
-rw-r--r--nuklear/extra_font/Raleway-Bold.ttfbin0 -> 176280 bytes
-rw-r--r--nuklear/extra_font/Roboto-Bold.ttfbin0 -> 135820 bytes
-rw-r--r--nuklear/extra_font/Roboto-Light.ttfbin0 -> 140276 bytes
-rw-r--r--nuklear/extra_font/Roboto-Regular.ttfbin0 -> 145348 bytes
-rw-r--r--nuklear/extra_font/kenvector_future.ttfbin0 -> 34136 bytes
-rw-r--r--nuklear/extra_font/kenvector_future_thin.ttfbin0 -> 34100 bytes
-rw-r--r--nuklear/nuklear.h22113
-rw-r--r--nuklear/package.json8
-rw-r--r--osc.lv2/CMakeLists.txt16
-rw-r--r--osc.lv2/COPYING201
-rw-r--r--osc.lv2/README.md3
-rw-r--r--osc.lv2/lv2-osc.doap.ttl40
-rw-r--r--osc.lv2/manifest.ttl23
-rw-r--r--osc.lv2/osc.lv2/endian.h129
-rw-r--r--osc.lv2/osc.lv2/forge.h474
-rw-r--r--osc.lv2/osc.lv2/osc.h192
-rw-r--r--osc.lv2/osc.lv2/reader.h570
-rw-r--r--osc.lv2/osc.lv2/util.h481
-rw-r--r--osc.lv2/osc.lv2/writer.h557
-rw-r--r--osc.lv2/osc.ttl42
-rw-r--r--osc.lv2/osc_test.c423
-rw-r--r--osc_inspector.c252
-rw-r--r--osc_inspector_nk.c399
-rw-r--r--props.lv2/CMakeLists.txt41
-rw-r--r--props.lv2/COPYING201
-rw-r--r--props.lv2/README.md20
-rw-r--r--props.lv2/props.h957
-rw-r--r--props.lv2/test/chunk.binbin0 -> 16 bytes
-rw-r--r--props.lv2/test/manifest.ttl.in28
-rw-r--r--props.lv2/test/props.c321
-rw-r--r--props.lv2/test/props.ttl152
-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
-rw-r--r--sherlock.c39
-rw-r--r--sherlock.h94
-rw-r--r--sherlock.ttl248
-rw-r--r--sherlock_nk.c591
-rw-r--r--sherlock_nk.h142
-rw-r--r--sherlock_ui.ttl59
169 files changed, 58072 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..9b79cef
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,75 @@
+stages:
+ - build
+ - deploy
+
+.variables_template: &variables_definition
+ variables:
+ BASE_NAME: "sherlock.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"
+
+.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
+ before_script:
+ - apt-get update
+ - apt-get install -y -q flex
+ script:
+ - mkdir build
+ - pushd build
+ - 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} ..
+ - cmake .. # needed for darwin
+ - make
+ - make install
+
+.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/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..56f7df8
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,156 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(sherlock.lv2)
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/osc.lv2)
+include_directories(${PROJECT_SOURCE_DIR}/props.lv2)
+include_directories(${PROJECT_SOURCE_DIR}/pugl)
+
+set(CMAKE_FIND_FRAMEWORK FIRST)
+
+set(CMAKE_C_FLAGS "-fdata-sections -ffunction-sections ${CMAKE_C_FLAGS}")
+set(CMAKE_C_FLAGS "-std=gnu11 -Wextra -Wno-unused-parameter -ffast-math -fvisibility=hidden ${CMAKE_C_FLAGS}")
+set(CMAKE_C_FLAGS "-Wshadow -Wimplicit-function-declaration -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes ${CMAKE_C_FLAGS}")
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-z,defs ${CMAKE_MODULE_LINKER_FLAGS}")
+ set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-z,nodelete ${CMAKE_MODULE_LINKER_FLAGS}")
+elseif(WIN32)
+ set(CMAKE_C_FLAGS "-mstackrealign ${CMAKE_C_FLAGS}")
+endif()
+
+if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ if(APPLE)
+ set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-dead_strip ${CMAKE_MODULE_LINKER_FLAGS}")
+ else()
+ set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--gc-sections -Wl,-s ${CMAKE_MODULE_LINKER_FLAGS}")
+ endif()
+endif()
+
+add_definitions("-D_GNU_SOURCE=1") # asprintf
+
+if(WIN32)
+ set(SHERLOCK_UI_TYPE "WindowsUI")
+elseif(APPLE)
+ set(SHERLOCK_UI_TYPE "CocoaUI")
+else()
+ set(SHERLOCK_UI_TYPE "X11UI")
+endif()
+
+file(STRINGS "VERSION" SHERLOCK_VERSION)
+string(REPLACE "." ";" VERSION_LIST ${SHERLOCK_VERSION})
+list(GET VERSION_LIST 0 SHERLOCK_MAJOR_VERSION)
+list(GET VERSION_LIST 1 SHERLOCK_MINOR_VERSION)
+list(GET VERSION_LIST 2 SHERLOCK_MICRO_VERSION)
+add_definitions("-DSHERLOCK_VERSION=\"${SHERLOCK_VERSION}\"")
+
+if(NOT DEFINED PLUGIN_DEST)
+ set(PLUGIN_DEST lib/lv2/sherlock.lv2)
+endif()
+
+find_package(PkgConfig) # ${PKG_CONFIG_FOUND}
+
+
+set(LIBS_UI m)
+
+pkg_search_module(LV2 REQUIRED lv2>=1.10)
+include_directories(${LV2_INCLUDE_DIRS})
+
+find_package(OpenGL)
+if(${OPENGL_FOUND})
+ set(LIBS_UI ${LIBS_UI} ${OPENGL_LIBRARIES})
+else() # try pkg-config
+ pkg_search_module(GL REQUIRED gl)
+ if(${GL_FOUND})
+ set(LIBS_UI ${LIBS_UI} ${GL_LDFLAGS})
+ else()
+ message(FATAL_ERROR "OpenGL not found")
+ endif()
+endif()
+add_definitions("-DPUGL_HAVE_GL")
+
+if(WIN32)
+ find_library(GDI32_LIBRARY NAMES gdi32)
+ if(GDI32_LIBRARY)
+ set(LIBS_UI ${LIBS_UI} ${GDI32_LIBRARY})
+ else()
+ message(FATAL_ERROR "gdi32 library not found")
+ endif()
+
+ find_library(USER32_LIBRARY NAMES user32)
+ if(USER32_LIBRARY)
+ set(LIBS_UI ${LIBS_UI} ${USER32_LIBRARY})
+ else()
+ message(FATAL_ERROR "user32 library not found")
+ endif()
+
+ set(TAR_UI ${TAR_UI} pugl/pugl/pugl_win.cpp)
+
+elseif(APPLE)
+ find_library(COCOA_LIBRARY NAMES Cocoa)
+ if(COCOA_LIBRARY)
+ set(LIBS_UI ${LIBS_UI} ${COCOA_LIBRARY})
+ else()
+ message(FATAL_ERROR "Cocoa framework not found")
+ endif()
+
+ set(TAR_UI ${TAR_UI} pugl/pugl/pugl_osx.m)
+
+else() # GNU/Linux
+ pkg_search_module(X11 REQUIRED x11>=1.6)
+ include_directories(${X11_INCLUDE_DIRS})
+ set(LIBS_UI ${LIBS_UI} ${X11_LDFLAGS})
+
+ pkg_search_module(XEXT REQUIRED xext>=1.3)
+ include_directories(${XEXT_INCLUDE_DIRS})
+ set(LIBS_UI ${LIBS_UI} ${XEXT_LDFLAGS})
+
+ set(TAR_UI ${TAR_UI} pugl/pugl/pugl_x11.c)
+endif()
+
+pkg_search_module(SRATOM REQUIRED sratom-0>=0.4.0)
+include_directories(${SRATOM_INCLUDE_DIRS})
+if(DEFINED STATIC_SRATOM)
+ set(LIBS_UI ${STATIC_SRATOM} ${STATIC_SORD} ${STATIC_SERD} ${LIBS_UI})
+else()
+ set(LIBS_UI ${LIBS_UI} ${SRATOM_LDFLAGS})
+endif()
+
+
+add_library(sherlock MODULE
+ sherlock.c
+ atom_inspector.c
+ midi_inspector.c
+ osc_inspector.c)
+set_target_properties(sherlock PROPERTIES PREFIX "")
+if(NOT WIN32)
+ set_target_properties(sherlock PROPERTIES LINK_FLAGS "-Wl,-e,lv2_descriptor")
+endif()
+install(TARGETS sherlock DESTINATION ${PLUGIN_DEST})
+
+find_package(FLEX)
+flex_target(encoder encoder.l ${PROJECT_BINARY_DIR}/encoder.c
+ COMPILE_FLAGS "--prefix=enc")
+
+add_library(sherlock_nk MODULE
+ sherlock_nk.c
+ midi_inspector_nk.c
+ atom_inspector_nk.c
+ osc_inspector_nk.c
+ encoder
+ ${TAR_UI})
+target_link_libraries(sherlock_nk
+ ${LIBS_UI})
+set_target_properties(sherlock_nk PROPERTIES PREFIX "")
+if(NOT WIN32)
+ set_target_properties(sherlock_nk PROPERTIES LINK_FLAGS "-Wl,-e,lv2ui_descriptor")
+endif()
+install(TARGETS sherlock_nk DESTINATION ${PLUGIN_DEST})
+
+configure_file(${PROJECT_SOURCE_DIR}/manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl)
+install(FILES ${PROJECT_BINARY_DIR}/manifest.ttl DESTINATION ${PLUGIN_DEST})
+install(FILES ${PROJECT_SOURCE_DIR}/sherlock.ttl DESTINATION ${PLUGIN_DEST})
+install(FILES ${PROJECT_SOURCE_DIR}/sherlock_ui.ttl DESTINATION ${PLUGIN_DEST})
+
+install(FILES ${PROJECT_SOURCE_DIR}/nuklear/extra_font/Cousine-Regular.ttf DESTINATION ${PLUGIN_DEST})
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2c57307
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# Sherlock
+
+## An investigative LV2 plugin bundle
+
+### Webpage
+
+Get more information at: [http://open-music-kontrollers.ch/lv2/sherlock](http://open-music-kontrollers.ch/lv2/sherlock)
+
+### Build status
+
+[![build status](https://gitlab.com/OpenMusicKontrollers/sherlock.lv2/badges/master/build.svg)](https://gitlab.com/OpenMusicKontrollers/sherlock.lv2/commits/master)
+
+### Dependencies
+
+* [LV2](http://lv2plug.in) (LV2 Plugin Standard)
+* [pugl](http://drobilla.net/software/pugl) (Portable API for OpenGL GUIs)
+* [nuklear](https://github.com/vurtun/nuklear) (Immediate-mode GUI)
+
+### Build / install
+
+ git clone https://github.com/OpenMusicKontrollers/sherlock.lv2.git
+ cd sherlock.lv2
+ mkdir build
+ cd build
+ make
+ sudo make install
+
+### License
+
+Copyright (c) 2015-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..396c7f3
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.13.53
diff --git a/atom_inspector.c b/atom_inspector.c
new file mode 100644
index 0000000..3c18ad5
--- /dev/null
+++ b/atom_inspector.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2015-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 <stdio.h>
+#include <stdlib.h>
+
+#include <sherlock.h>
+
+typedef struct _handle_t handle_t;
+
+struct _handle_t {
+ LV2_URID_Map *map;
+ const LV2_Atom_Sequence *control_in;
+ LV2_Atom_Sequence *control_out;
+ LV2_Atom_Sequence *notify;
+ LV2_Atom_Forge forge;
+
+ LV2_URID time_position;
+ LV2_URID time_frame;
+
+ int64_t frame;
+
+ PROPS_T(props, MAX_NPROPS);
+ state_t state;
+ state_t stash;
+};
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor, double rate,
+ const char *bundle_path, const LV2_Feature *const *features)
+{
+ int i;
+ handle_t *handle = calloc(1, sizeof(handle_t));
+ if(!handle)
+ return NULL;
+
+ for(i=0; features[i]; i++)
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->map = (LV2_URID_Map *)features[i]->data;
+
+ if(!handle->map)
+ {
+ fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+
+ handle->time_position = handle->map->map(handle->map->handle, LV2_TIME__Position);
+ handle->time_frame = handle->map->map(handle->map->handle, LV2_TIME__frame);
+
+ lv2_atom_forge_init(&handle->forge, handle->map);
+
+ if(!props_init(&handle->props, descriptor->URI,
+ defs, MAX_NPROPS, &handle->state, &handle->stash,
+ handle->map, handle))
+ {
+ fprintf(stderr, "failed to allocate property structure\n");
+ free(handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void *data)
+{
+ handle_t *handle = (handle_t *)instance;
+
+ switch(port)
+ {
+ case 0:
+ handle->control_in = (const LV2_Atom_Sequence *)data;
+ break;
+ case 1:
+ handle->control_out = (LV2_Atom_Sequence *)data;
+ break;
+ case 2:
+ handle->notify = (LV2_Atom_Sequence *)data;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+run(LV2_Handle instance, uint32_t nsamples)
+{
+ handle_t *handle = (handle_t *)instance;
+ uint32_t capacity;
+ LV2_Atom_Forge *forge = &handle->forge;
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom_Forge_Ref ref;
+
+ // size of input sequence
+ const size_t size = lv2_atom_total_size(&handle->control_in->atom);
+
+ capacity = handle->control_out->atom.size;
+ lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->control_out, capacity);
+ ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
+
+ props_idle(&handle->props, forge, 0, &ref);
+
+ LV2_ATOM_SEQUENCE_FOREACH(handle->control_in, ev)
+ {
+ const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
+ const int64_t frames = ev->time.frames;
+
+ // copy all events to through port
+ if(ref)
+ ref = lv2_atom_forge_frame_time(forge, frames);
+ if(ref)
+ ref = lv2_atom_forge_raw(forge, &obj->atom, lv2_atom_total_size(&obj->atom));
+ if(ref)
+ lv2_atom_forge_pad(forge, obj->atom.size);
+
+ if( !props_advance(&handle->props, forge, frames, obj, &ref)
+ && lv2_atom_forge_is_object_type(forge, obj->atom.type)
+ && (obj->body.otype == handle->time_position) )
+ {
+ const LV2_Atom_Long *time_frame = NULL;
+ lv2_atom_object_get(obj, handle->time_frame, &time_frame, NULL);
+ if(time_frame)
+ handle->frame = time_frame->body - frames;
+ }
+ }
+
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+ else
+ lv2_atom_sequence_clear(handle->control_out);
+
+ // forge whole sequence as single event
+ capacity = handle->notify->atom.size;
+ lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->notify, capacity);
+ ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
+
+ // only serialize sequence to UI if there were actually any events
+ if(handle->control_in->atom.size > sizeof(LV2_Atom_Sequence_Body))
+ {
+ LV2_Atom_Forge_Frame tup_frame;
+
+ if(ref)
+ ref = lv2_atom_forge_frame_time(forge, 0);
+ if(ref)
+ ref = lv2_atom_forge_tuple(forge, &tup_frame);
+ if(ref)
+ ref = lv2_atom_forge_long(forge, handle->frame);
+ if(ref)
+ ref = lv2_atom_forge_int(forge, nsamples);
+ if(ref)
+ ref = lv2_atom_forge_write(forge, handle->control_in, size);
+ if(ref)
+ lv2_atom_forge_pop(forge, &tup_frame);
+
+ }
+
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+ else
+ lv2_atom_sequence_clear(handle->notify);
+
+ handle->frame += nsamples;
+}
+
+static void
+cleanup(LV2_Handle instance)
+{
+ handle_t *handle = (handle_t *)instance;
+
+ free(handle);
+}
+
+static LV2_State_Status
+_state_save(LV2_Handle instance, LV2_State_Store_Function store,
+ LV2_State_Handle state, uint32_t flags,
+ const LV2_Feature *const *features)
+{
+ handle_t *handle = instance;
+
+ return props_save(&handle->props, store, state, flags, features);
+}
+
+static LV2_State_Status
+_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
+ LV2_State_Handle state, uint32_t flags,
+ const LV2_Feature *const *features)
+{
+ handle_t *handle = instance;
+
+ return props_restore(&handle->props, retrieve, state, flags, features);
+}
+
+static const LV2_State_Interface state_iface = {
+ .save = _state_save,
+ .restore = _state_restore
+};
+
+static const void*
+extension_data(const char* uri)
+{
+ if(!strcmp(uri, LV2_STATE__interface))
+ return &state_iface;
+
+ return NULL;
+}
+
+const LV2_Descriptor atom_inspector = {
+ .URI = SHERLOCK_ATOM_INSPECTOR_URI,
+ .instantiate = instantiate,
+ .connect_port = connect_port,
+ .activate = NULL,
+ .run = run,
+ .deactivate = NULL,
+ .cleanup = cleanup,
+ .extension_data = extension_data
+};
diff --git a/atom_inspector_nk.c b/atom_inspector_nk.c
new file mode 100644
index 0000000..fc886dd
--- /dev/null
+++ b/atom_inspector_nk.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2015-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 <ctype.h>
+#include <inttypes.h>
+
+#include <sherlock.h>
+#include <sherlock_nk.h>
+#include <encoder.h>
+
+#ifdef Bool // hack for xlib
+# undef Bool
+#endif
+
+#define NS_RDF (const uint8_t*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#define NS_RDFS (const uint8_t*)"http://www.w3.org/2000/01/rdf-schema#"
+#define NS_XSD (const uint8_t*)"http://www.w3.org/2001/XMLSchema#"
+#define NS_OSC (const uint8_t*)"http://open-music-kontrollers.ch/lv2/osc#"
+#define NS_XPRESS (const uint8_t*)"http://open-music-kontrollers.ch/lv2/xpress#"
+#define NS_SPOD (const uint8_t*)"http://open-music-kontrollers.ch/lv2/synthpod#"
+#define NS_CANVAS (const uint8_t*)"http://open-music-kontrollers.ch/lv2/canvas#"
+
+// copyied and adapted from libsratom
+static inline char *
+_sratom_to_turtle(Sratom* sratom,
+ LV2_URID_Unmap* unmap,
+ const char* base_uri,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ uint32_t type,
+ uint32_t size,
+ const void* body)
+{
+ SerdURI buri = SERD_URI_NULL;
+ SerdNode base = serd_node_new_uri_from_string((uint8_t *)(base_uri), NULL, &buri);
+ SerdEnv* env = serd_env_new(&base);
+ SerdChunk str = { NULL, 0 };
+
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"rdf", NS_RDF);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"rdfs", NS_RDFS);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"xsd", NS_XSD);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"lv2", (const uint8_t *)LV2_CORE_PREFIX);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"midi", (const uint8_t *)LV2_MIDI_PREFIX);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"atom", (const uint8_t *)LV2_ATOM_PREFIX);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"units", (const uint8_t *)LV2_UNITS_PREFIX);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"ui", (const uint8_t *)LV2_UI_PREFIX);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"time", (const uint8_t *)LV2_TIME_URI"#");
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"patch", (const uint8_t *)LV2_PATCH_PREFIX);
+
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"osc", NS_OSC);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"xpress", NS_XPRESS);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"spod", NS_SPOD);
+ serd_env_set_prefix_from_strings(env, (const uint8_t *)"canvas", NS_CANVAS);
+
+ SerdWriter* writer = serd_writer_new(
+ SERD_TURTLE,
+ (SerdStyle)(SERD_STYLE_ABBREVIATED |
+ SERD_STYLE_RESOLVED |
+ SERD_STYLE_CURIED |
+ SERD_STYLE_ASCII),
+ env, &buri, serd_chunk_sink, &str);
+
+ // Write @prefix directives
+ serd_env_foreach(env,
+ (SerdPrefixSink)serd_writer_set_prefix,
+ writer);
+
+ sratom_set_sink(sratom, base_uri,
+ (SerdStatementSink)serd_writer_write_statement,
+ (SerdEndSink)serd_writer_end_anon,
+ writer);
+ sratom_write(sratom, unmap, SERD_EMPTY_S,
+ subject, predicate, type, size, body);
+ serd_writer_finish(writer);
+
+ serd_writer_free(writer);
+ serd_env_free(env);
+ serd_node_free(&base);
+ return (char*)serd_chunk_sink_finish(&str);
+}
+
+static void
+_set_string(struct nk_str *str, uint32_t size, const char *body)
+{
+ nk_str_clear(str);
+
+ // replace tab with 2 spaces
+ const char *end = body + size - 1;
+ const char *from = body;
+ for(const char *to = strchr(from, '\t');
+ to && (to < end);
+ from = to + 1, to = strchr(from, '\t'))
+ {
+ nk_str_append_text_utf8(str, from, to-from);
+ nk_str_append_text_utf8(str, " ", 2);
+ }
+ nk_str_append_text_utf8(str, from, end-from);
+}
+
+void
+_atom_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
+{
+ plughandle_t *handle = data;
+
+ handle->dy = 20.f * _get_scale(handle);
+ const float widget_h = handle->dy;
+ struct nk_style *style = &ctx->style;
+ const struct nk_vec2 window_padding = style->window.padding;
+ const struct nk_vec2 group_padding = style->window.group_padding;
+
+ style->selectable.normal.data.color.a = 0x0;
+ style->selectable.hover.data.color.a = 0x0;
+
+ if(nk_begin(ctx, "Window", wbounds, NK_WINDOW_NO_SCROLLBAR))
+ {
+ nk_window_set_bounds(ctx, wbounds);
+ struct nk_panel *panel= nk_window_get_panel(ctx);
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
+
+ const float body_h = panel->bounds.h - 2*window_padding.y;
+ nk_layout_row_dynamic(ctx, body_h, 2);
+ if(nk_group_begin(ctx, "Left", NK_WINDOW_NO_SCROLLBAR))
+ {
+ const float content_h = nk_window_get_height(ctx) - 2*window_padding.y - 4*group_padding.y - 2*widget_h;
+ nk_layout_row_dynamic(ctx, content_h, 1);
+ nk_flags flags = NK_WINDOW_BORDER;
+ if(handle->state.follow)
+ flags |= NK_WINDOW_NO_SCROLLBAR;
+ struct nk_list_view lview;
+ if(nk_list_view_begin(ctx, &lview, "Events", flags, widget_h, NK_MIN(handle->n_item, MAX_LINES)))
+ {
+ if(handle->state.follow)
+ {
+ lview.end = NK_MAX(handle->n_item, 0);
+ lview.begin = NK_MAX(lview.end - lview.count, 0);
+ }
+ for(int l = lview.begin; (l < lview.end) && (l < handle->n_item); l++)
+ {
+ item_t *itm = handle->items[l];
+
+ switch(itm->type)
+ {
+ case ITEM_TYPE_NONE:
+ {
+ // skip, never reached
+ } break;
+ case ITEM_TYPE_FRAME:
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 3);
+ {
+ struct nk_rect b = nk_widget_bounds(ctx);
+ b.x -= group_padding.x;
+ b.w *= 3;
+ b.w += 4*group_padding.x;
+ nk_fill_rect(canvas, b, 0.f, nk_rgb(0x18, 0x18, 0x18));
+ }
+
+ nk_labelf_colored(ctx, NK_TEXT_LEFT, orange, "@%"PRIi64, itm->frame.offset);
+ nk_labelf_colored(ctx, NK_TEXT_CENTERED, green, "-%"PRIu32"-", itm->frame.counter);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%"PRIi32, itm->frame.nsamples);
+ } break;
+
+ case ITEM_TYPE_EVENT:
+ {
+ LV2_Atom_Event *ev = &itm->event.ev;
+ const LV2_Atom *body = &ev->body;
+ const int64_t frames = ev->time.frames;
+ const char *uri = NULL;
+ if(lv2_atom_forge_is_object_type(&handle->forge, body->type))
+ {
+ const LV2_Atom_Object *obj = (const LV2_Atom_Object *)body;
+
+ if(obj->body.otype)
+ uri = handle->unmap->unmap(handle->unmap->handle, obj->body.otype);
+ else if(obj->body.id)
+ uri = handle->unmap->unmap(handle->unmap->handle, obj->body.id);
+ else
+ uri = "Unknown";
+ }
+ else // not an object
+ {
+ uri = handle->unmap->unmap(handle->unmap->handle, body->type);
+ }
+
+ const bool is_primitive = (body->type == handle->forge.Bool)
+ || (body->type == handle->forge.Int)
+ || (body->type == handle->forge.Long)
+ || (body->type == handle->forge.Float)
+ || (body->type == handle->forge.Double)
+ || (body->type == handle->forge.String)
+ || (body->type == handle->forge.URI)
+ || (body->type == handle->forge.URID)
+ || (body->type == handle->forge.Path)
+ || (body->type == handle->forge.Literal);
+
+ nk_layout_row_begin(ctx, NK_DYNAMIC, widget_h, 3 + is_primitive);
+ {
+ nk_layout_row_push(ctx, 0.1);
+ if(l % 2 == 0)
+ {
+ struct nk_rect b = nk_widget_bounds(ctx);
+ b.x -= group_padding.x;
+ b.w *= 10;
+ b.w += 8*group_padding.x;
+ nk_fill_rect(canvas, b, 0.f, nk_rgb(0x28, 0x28, 0x28));
+ }
+ nk_labelf_colored(ctx, NK_TEXT_LEFT, yellow, "+%04"PRIi64, frames);
+
+ nk_layout_row_push(ctx, is_primitive ? 0.6 : 0.8);
+ if(nk_select_label(ctx, uri, NK_TEXT_LEFT, handle->selected == body))
+ {
+ handle->ttl_dirty = handle->ttl_dirty
+ || (handle->selected != body); // has selection actually changed?
+ handle->selected = body;
+ }
+
+ if(is_primitive)
+ {
+ const struct nk_color col = nk_rgb(0xff, 0xff, 0xff);
+
+ nk_layout_row_push(ctx, 0.2);
+ if(body->type == handle->forge.Bool)
+ {
+ const LV2_Atom_Bool *ref = (const LV2_Atom_Bool *)body;
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%s", ref->body ? "true" : "false");
+ }
+ else if(body->type == handle->forge.Int)
+ {
+ const LV2_Atom_Int *ref = (const LV2_Atom_Int *)body;
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%"PRIi32, ref->body);
+ }
+ else if(body->type == handle->forge.Long)
+ {
+ const LV2_Atom_Long *ref = (const LV2_Atom_Long *)body;
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%"PRIi64, ref->body);
+ }
+ else if(body->type == handle->forge.Float)
+ {
+ const LV2_Atom_Float *ref = (const LV2_Atom_Float *)body;
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%f", ref->body);
+ }
+ else if(body->type == handle->forge.Double)
+ {
+ const LV2_Atom_Double *ref = (const LV2_Atom_Double *)body;
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, green, "%lf", ref->body);
+ }
+ else if(body->type == handle->forge.String)
+ {
+ nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, red);
+ }
+ else if(body->type == handle->forge.URI)
+ {
+ nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, yellow);
+ }
+ else if(body->type == handle->forge.URID)
+ {
+ const char *_uri = "urn"; //FIXME
+ nk_label_colored(ctx, _uri, NK_TEXT_RIGHT, yellow);
+ }
+ else if(body->type == handle->forge.Path)
+ {
+ nk_label_colored(ctx, LV2_ATOM_BODY_CONST(body), NK_TEXT_RIGHT, red);
+ }
+ else if(body->type == handle->forge.Literal)
+ {
+ nk_label_colored(ctx, LV2_ATOM_CONTENTS_CONST(LV2_Atom_Literal, body), NK_TEXT_RIGHT, red);
+ }
+ }
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, body->size);
+ }
+ nk_layout_row_end(ctx);
+ } break;
+ }
+ }
+
+ nk_list_view_end(&lview);
+ }
+
+ nk_layout_row_dynamic(ctx, widget_h, 4);
+ {
+ if(nk_checkbox_label(ctx, "overwrite", &handle->state.overwrite))
+ _toggle(handle, handle->urid.overwrite, handle->state.overwrite, true);
+ if(nk_checkbox_label(ctx, "block", &handle->state.block))
+ _toggle(handle, handle->urid.block, handle->state.block, true);
+ if(nk_checkbox_label(ctx, "follow", &handle->state.follow))
+ _toggle(handle, handle->urid.follow, handle->state.follow, true);
+ if(nk_checkbox_label(ctx, "pretty", &handle->pretty_numbers))
+ {
+ handle->ttl_dirty = true;
+ sratom_set_pretty_numbers(handle->sratom, handle->pretty_numbers);
+ }
+ }
+
+ const bool max_reached = handle->n_item >= MAX_LINES;
+ nk_layout_row_dynamic(ctx, widget_h, 2);
+ if(nk_button_symbol_label(ctx,
+ max_reached ? NK_SYMBOL_TRIANGLE_RIGHT: NK_SYMBOL_NONE,
+ "clear", NK_TEXT_LEFT))
+ {
+ _clear(handle);
+ }
+ nk_label(ctx, "Sherlock.lv2: "SHERLOCK_VERSION, NK_TEXT_RIGHT);
+
+ nk_group_end(ctx);
+ }
+
+ if(nk_group_begin(ctx, "Right", NK_WINDOW_NO_SCROLLBAR))
+ {
+ const LV2_Atom *atom = handle->selected;
+ if(handle->ttl_dirty && atom)
+ {
+ char *ttl = _sratom_to_turtle(handle->sratom, handle->unmap,
+ handle->base_uri, NULL, NULL,
+ atom->type, atom->size, LV2_ATOM_BODY_CONST(atom));
+ if(ttl)
+ {
+ struct nk_str *str = &handle->editor.string;
+ const size_t len = strlen(ttl);
+
+ _set_string(str, len, ttl);
+
+ handle->editor.lexer.needs_refresh = 1;
+
+ free(ttl);
+ }
+
+ handle->ttl_dirty = false;
+ }
+
+ const nk_flags flags = NK_EDIT_EDITOR;
+ char *str = nk_str_get(&handle->editor.string);
+ int len = nk_str_len(&handle->editor.string);
+
+ if(len > 0) //FIXME
+ {
+ const float content_h = nk_window_get_height(ctx) - 2*window_padding.y - 2*group_padding.y;
+ nk_layout_row_dynamic(ctx, content_h, 1);
+ nk_edit_focus(ctx, flags);
+ const nk_flags mode = nk_edit_buffer(ctx, flags, &handle->editor, nk_filter_default);
+ (void)mode;
+ }
+
+ nk_group_end(ctx);
+ }
+ }
+ nk_end(ctx);
+}
diff --git a/cmake/arm-linux-gnueabihf.cmake b/cmake/arm-linux-gnueabihf.cmake
new file mode 100644
index 0000000..f6d0b2a
--- /dev/null
+++ b/cmake/arm-linux-gnueabihf.cmake
@@ -0,0 +1,22 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR "armv7h")
+set(TOOLCHAIN "arm-linux-gnueabihf")
+
+# which compilers to use for C and C++
+set(CMAKE_C_COMPILER "${TOOLCHAIN}-gcc")
+set(CMAKE_CXX_COMPILER "${TOOLCHAIN}-g++")
+
+# here is the target environment located
+set(CMAKE_FIND_ROOT_PATH "usr/${TOOLCHAIN}")
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
diff --git a/cmake/i686-linux-gnu.cmake b/cmake/i686-linux-gnu.cmake
new file mode 100644
index 0000000..f00ae3e
--- /dev/null
+++ b/cmake/i686-linux-gnu.cmake
@@ -0,0 +1,11 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR "i686")
+set(TOOLCHAIN "i686-linux-gnu")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags")
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
diff --git a/cmake/i686-w64-mingw32.cmake b/cmake/i686-w64-mingw32.cmake
new file mode 100644
index 0000000..3564cad
--- /dev/null
+++ b/cmake/i686-w64-mingw32.cmake
@@ -0,0 +1,25 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR "i686")
+set(TOOLCHAIN "i686-w64-mingw32")
+
+# which compilers to use for C and C++
+set(CMAKE_C_COMPILER "${TOOLCHAIN}-gcc")
+set(CMAKE_CXX_COMPILER "${TOOLCHAIN}-g++")
+set(CMAKE_RC_COMPILER "${TOOLCHAIN}-windres")
+
+# here is the target environment located
+set(CMAKE_FIND_ROOT_PATH "/usr/${TOOLCHAIN}")
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
+
+set(WINE wine32)
diff --git a/cmake/universal-apple-darwin.cmake b/cmake/universal-apple-darwin.cmake
new file mode 100644
index 0000000..127e80f
--- /dev/null
+++ b/cmake/universal-apple-darwin.cmake
@@ -0,0 +1,24 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Darwin)
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+set(TOOLCHAIN "universal-apple-darwin")
+
+set(CMAKE_OSX_ARCHITECTURES "x86_64;i386")
+
+# which compilers to use for C and C++
+set(CMAKE_C_COMPILER "/usr/${TOOLCHAIN}/bin/x86_64-apple-darwin15-clang")
+set(CMAKE_CXX_COMPILER "/usr/${TOOLCHAIN}/bin/x86_64-apple-darwin15-clang++")
+
+# here is the target environment located
+set(CMAKE_FIND_ROOT_PATH "/usr/${TOOLCHAIN}/SDK/MacOSX10.11.sdk")
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
diff --git a/cmake/x86_64-linux-gnu.cmake b/cmake/x86_64-linux-gnu.cmake
new file mode 100644
index 0000000..730a594
--- /dev/null
+++ b/cmake/x86_64-linux-gnu.cmake
@@ -0,0 +1,8 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+set(TOOLCHAIN "x86_64-linux-gnu")
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
diff --git a/cmake/x86_64-w64-mingw32.cmake b/cmake/x86_64-w64-mingw32.cmake
new file mode 100644
index 0000000..9e90894
--- /dev/null
+++ b/cmake/x86_64-w64-mingw32.cmake
@@ -0,0 +1,25 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+set(TOOLCHAIN "x86_64-w64-mingw32")
+
+# which compilers to use for C and C++
+set(CMAKE_C_COMPILER "${TOOLCHAIN}-gcc")
+set(CMAKE_CXX_COMPILER "${TOOLCHAIN}-g++")
+set(CMAKE_RC_COMPILER "${TOOLCHAIN}-windres")
+
+# here is the target environment located
+set(CMAKE_FIND_ROOT_PATH "/usr/${TOOLCHAIN}")
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+set(STATIC_SRATOM "/opt/${TOOLCHAIN}/lib/libsratom-0.a")
+set(STATIC_SERD "/opt/${TOOLCHAIN}/lib/libserd-0.a")
+set(STATIC_SORD "/opt/${TOOLCHAIN}/lib/libsord-0.a")
+
+set(WINE wine64)
diff --git a/encoder.h b/encoder.h
new file mode 100644
index 0000000..43d26c4
--- /dev/null
+++ b/encoder.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-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 ENCODER_H
+#define ENCODER_H
+
+#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
+#include "nk_pugl/nk_pugl.h"
+
+extern const struct nk_color white;
+extern const struct nk_color gray;
+extern const struct nk_color yellow;
+extern const struct nk_color magenta;
+extern const struct nk_color green;
+extern const struct nk_color blue;
+extern const struct nk_color orange;
+extern const struct nk_color violet;
+extern const struct nk_color red;
+
+struct nk_token *
+ttl_lex(void *data, const char *utf8, int len);
+
+#endif
diff --git a/encoder.l b/encoder.l
new file mode 100644
index 0000000..d576fb4
--- /dev/null
+++ b/encoder.l
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015-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 <stdio.h>
+#include <string.h>
+
+#include <encoder.h>
+
+#define ful 0xff
+#define one 0xbb
+#define two 0x66
+#define non 0x0
+const struct nk_color white = {.r = one, .g = one, .b = one, .a = ful};
+const struct nk_color gray = {.r = two, .g = two, .b = two, .a = ful};
+const struct nk_color yellow = {.r = one, .g = one, .b = non, .a = ful};
+const struct nk_color magenta = {.r = one, .g = two, .b = one, .a = ful};
+const struct nk_color green = {.r = non, .g = one, .b = non, .a = ful};
+const struct nk_color blue = {.r = non, .g = one, .b = one, .a = ful};
+const struct nk_color orange = {.r = one, .g = two, .b = non, .a = ful};
+const struct nk_color violet = {.r = two, .g = two, .b = one, .a = ful};
+const struct nk_color red = {.r = one, .g = non, .b = non, .a = ful};
+
+enum {
+ TK_NONE,
+ TK_PREFIX,
+ TK_SUBJECT,
+ TK_PREDICATE,
+ TK_BOOL,
+ TK_NUMBER,
+ TK_URI_IN,
+ TK_URI_OUT,
+ TK_URI_ERR,
+ TK_STRING_IN,
+ TK_STRING_OUT,
+ TK_STRING_ERR,
+ TK_LONG_STRING_IN,
+ TK_LONG_STRING_OUT,
+ TK_WHITESPACE,
+ TK_RAW
+};
+
+%}
+
+%option reentrant noyywrap
+
+w [ \v\a]+
+name [_a-zA-Z@][_a-zA-Z0-9\.]*
+n [0-9]+
+exp [Ee][+-]?{n}
+number ({n}|{n}[.]{n}){exp}?
+eol [\n\r]
+
+%x XSTRING
+%x XLONG_STRING
+%x XURI
+
+%%
+
+{w} return TK_WHITESPACE;
+"\t" return TK_WHITESPACE;
+"<" BEGIN(XURI); return TK_URI_IN;
+\"\"\" BEGIN(XLONG_STRING); return TK_LONG_STRING_IN;
+\" BEGIN(XSTRING); return TK_STRING_IN;
+{name}: return TK_SUBJECT;
+"@prefix" return TK_PREFIX;
+"a" return TK_PREFIX;
+true return TK_BOOL;
+false return TK_BOOL;
+{name} return TK_PREDICATE;
+{number} return TK_NUMBER;
+. return TK_RAW;
+
+<XURI>
+{
+ ">" BEGIN(0); return TK_URI_OUT;
+ {eol} BEGIN(0); return TK_URI_ERR;
+ . return TK_RAW;
+}
+
+<XLONG_STRING>
+{
+ \\\" return TK_RAW;
+ \"\"\" BEGIN(0); return TK_LONG_STRING_OUT;
+ {w} return TK_WHITESPACE;
+ . return TK_RAW;
+}
+
+<XSTRING>
+{
+ \\\" return TK_RAW;
+ \" BEGIN(0); return TK_STRING_OUT;
+ {eol} BEGIN(0); return TK_STRING_ERR;
+ {w} return TK_WHITESPACE;
+ . return TK_RAW;
+}
+
+%%
+
+struct nk_token *
+ttl_lex(void *data, const char *utf8, int len)
+{
+ yyscan_t scanner;
+ YY_BUFFER_STATE buf;
+
+ enclex_init(&scanner);
+ if(utf8)
+ {
+ buf = enc_scan_bytes(utf8, len, scanner);
+ }
+ else
+ {
+ enclex_destroy(scanner);
+ return NULL;
+ }
+
+ struct nk_token *tokens = NULL;
+ int n_tokens = 0;
+
+ const char *base = encget_text(scanner);
+ int offset0 = 0;
+ struct nk_color col0 = {0xff, 0xff, 0xff, 0xff};
+
+ for(int tok=enclex(scanner); tok; tok=enclex(scanner))
+ {
+ const char *txt = encget_text(scanner);
+ const int offset1 = txt - base;
+ struct nk_color col1 = col0;
+
+ switch(tok)
+ {
+ case TK_PREFIX:
+ col1 = blue;
+ break;
+ case TK_SUBJECT:
+ col1 = magenta;
+ break;
+ case TK_PREDICATE:
+ col1 = orange;
+ break;
+ case TK_BOOL:
+ col1 = violet;
+ break;
+ case TK_NUMBER:
+ col1 = green;
+ break;
+ case TK_URI_IN:
+ case TK_URI_OUT:
+ case TK_URI_ERR:
+ col1 = yellow;
+ break;
+
+ case TK_STRING_IN:
+ case TK_STRING_OUT:
+ case TK_STRING_ERR:
+ case TK_LONG_STRING_IN:
+ case TK_LONG_STRING_OUT:
+ col1 = red;
+ break;
+
+ case TK_NONE:
+ case TK_WHITESPACE:
+ col1 = white;
+ break;
+
+ case TK_RAW:
+ default:
+ // skip over
+ break;
+ }
+
+ if(offset1)
+ {
+ tokens = realloc(tokens, (n_tokens + 1) * sizeof(struct nk_token));
+ tokens[n_tokens].offset = offset1;
+ tokens[n_tokens++].color = col0;
+ }
+
+ offset0 = offset1;
+ col0 = col1;
+ }
+
+ tokens = realloc(tokens, (n_tokens + 1) * sizeof(struct nk_token));
+ tokens[n_tokens].offset = len;
+ tokens[n_tokens++].color = (struct nk_color){0xff, 0xff, 0xff, 0xff};
+
+ enc_delete_buffer(buf, scanner);
+ enclex_destroy(scanner);
+
+ return tokens;
+}
diff --git a/manifest.ttl.in b/manifest.ttl.in
new file mode 100644
index 0000000..d71006b
--- /dev/null
+++ b/manifest.ttl.in
@@ -0,0 +1,62 @@
+# Copyright (c) 2015-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 rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
+
+@prefix sherlock: <http://open-music-kontrollers.ch/lv2/sherlock#> .
+
+# Atom Inspector Plugin
+sherlock:atom_inspector
+ a lv2:Plugin ;
+ lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
+ lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
+ lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ ui:ui sherlock:atom_inspector_4_nk ;
+ rdfs:seeAlso <sherlock.ttl> .
+
+sherlock:atom_inspector_4_nk
+ a ui:@SHERLOCK_UI_TYPE@ ;
+ ui:binary <sherlock_nk@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
+
+# MIDI Inspector Plugin
+sherlock:midi_inspector
+ a lv2:Plugin ;
+ lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
+ lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
+ lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ ui:ui sherlock:midi_inspector_4_nk ;
+ rdfs:seeAlso <sherlock.ttl> .
+
+sherlock:midi_inspector_4_nk
+ a ui:@SHERLOCK_UI_TYPE@ ;
+ ui:binary <sherlock_nk@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
+
+# OSC Inspector Plugin
+sherlock:osc_inspector
+ a lv2:Plugin ;
+ lv2:minorVersion @SHERLOCK_MINOR_VERSION@ ;
+ lv2:microVersion @SHERLOCK_MICRO_VERSION@ ;
+ lv2:binary <sherlock@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ ui:ui sherlock:osc_inspector_4_nk ;
+ rdfs:seeAlso <sherlock.ttl> .
+
+sherlock:osc_inspector_4_nk
+ a ui:@SHERLOCK_UI_TYPE@ ;
+ ui:binary <sherlock_nk@CMAKE_SHARED_MODULE_SUFFIX@> ;
+ rdfs:seeAlso <sherlock_ui.ttl> .
diff --git a/midi_inspector.c b/midi_inspector.c
new file mode 100644
index 0000000..95cd500
--- /dev/null
+++ b/midi_inspector.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015-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 <stdio.h>
+#include <stdlib.h>
+
+#include <sherlock.h>
+
+#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
+
+typedef struct _handle_t handle_t;
+
+struct _handle_t {
+ LV2_URID_Map *map;
+ const LV2_Atom_Sequence *control_in;
+ LV2_Atom_Sequence *control_out;
+ LV2_Atom_Sequence *notify;
+ LV2_Atom_Forge forge;
+
+ LV2_URID time_position;
+ LV2_URID time_frame;
+ LV2_URID midi_event;
+
+ int64_t frame;
+
+ PROPS_T(props, MAX_NPROPS);
+ state_t state;
+ state_t stash;
+};
+
+static LV2_Handle
+instantiate(const LV2_Descriptor* descriptor, double rate,
+ const char *bundle_path, const LV2_Feature *const *features)
+{
+ int i;
+ handle_t *handle = calloc(1, sizeof(handle_t));
+ if(!handle)
+ return NULL;
+
+ for(i=0; features[i]; i++)
+ if(!strcmp(features[i]->URI, LV2_URID__map))
+ handle->map = (LV2_URID_Map *)features[i]->data;
+
+ if(!handle->map)
+ {
+ fprintf(stderr, "%s: Host does not support urid:map\n", descriptor->URI);
+ free(handle);
+ return NULL;
+ }
+
+ handle->time_position = handle->map->map(handle->map->handle, LV2_TIME__Position);
+ handle->time_frame = handle->map->map(handle->map->handle, LV2_TIME__frame);
+
+ handle->midi_event = handle->map->map(handle->map->handle, LV2_MIDI__MidiEvent);
+
+ lv2_atom_forge_init(&handle->forge, handle->map);
+
+ if(!props_init(&handle->props, descriptor->URI,
+ defs, MAX_NPROPS, &handle->state, &handle->stash,
+ handle->map, handle))
+ {
+ fprintf(stderr, "failed to allocate property structure\n");
+ free(handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+static void
+connect_port(LV2_Handle instance, uint32_t port, void *data)
+{
+ handle_t *handle = (handle_t *)instance;
+
+ switch(port)
+ {
+ case 0:
+ handle->control_in = (const LV2_Atom_Sequence *)data;
+ break;
+ case 1:
+ handle->control_out = (LV2_Atom_Sequence *)data;
+ break;
+ case 2:
+ handle->notify = (LV2_Atom_Sequence *)data;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+run(LV2_Handle instance, uint32_t nsamples)
+{
+ handle_t *handle = (handle_t *)instance;
+ uint32_t capacity;
+ LV2_Atom_Forge *forge = &handle->forge;
+ LV2_Atom_Forge_Frame frame [3];
+ LV2_Atom_Forge_Ref ref;
+
+ // size of input sequence
+ const size_t size = lv2_atom_total_size(&handle->control_in->atom);
+
+ // copy whole input sequence to through port
+ capacity = handle->control_out->atom.size;
+ lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->control_out, capacity);
+ ref = lv2_atom_forge_sequence_head(forge, frame, 0);
+
+ props_idle(&handle->props, forge, 0, &ref);
+
+ LV2_ATOM_SEQUENCE_FOREACH(handle->control_in, ev)
+ {
+ const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
+ const int64_t frames = ev->time.frames;
+
+ // copy all events to through port
+ if(ref)
+ ref = lv2_atom_forge_frame_time(forge, frames);
+ if(ref)
+ ref = lv2_atom_forge_raw(forge, &obj->atom, lv2_atom_total_size(&obj->atom));
+ if(ref)
+ lv2_atom_forge_pad(forge, obj->atom.size);
+
+ if( !props_advance(&handle->props, forge, frames, obj, &ref)
+ && lv2_atom_forge_is_object_type(forge, obj->atom.type)
+ && (obj->body.otype == handle->time_position) )
+ {
+ const LV2_Atom_Long *time_frame = NULL;
+ lv2_atom_object_get(obj, handle->time_frame, &time_frame, NULL);
+ if(time_frame)
+ handle->frame = time_frame->body - frames;
+ }
+ }
+
+ if(ref)
+ lv2_atom_forge_pop(forge, frame);
+ else
+ lv2_atom_sequence_clear(handle->control_out);
+
+ // forge whole sequence as single event
+ capacity = handle->notify->atom.size;
+ lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->notify, capacity);
+
+ bool has_midi = false;
+
+ ref = lv2_atom_forge_sequence_head(forge, &frame[0], 0);
+ if(ref)
+ ref = lv2_atom_forge_frame_time(forge, 0);
+ if(ref)
+ ref = lv2_atom_forge_tuple(forge, &frame[1]);
+ if(ref)
+ ref = lv2_atom_forge_long(forge, handle->frame);
+ if(ref)
+ ref = lv2_atom_forge_int(forge, nsamples);
+ if(ref)
+ ref = lv2_atom_forge_sequence_head(forge, &frame[2], 0);
+
+ // only serialize MIDI events to UI
+ LV2_ATOM_SEQUENCE_FOREACH(handle->control_in, ev)
+ {
+ if(ev->body.type == handle->midi_event)
+ {
+ has_midi = true;
+ if(ref)
+ ref = lv2_atom_forge_frame_time(forge, ev->time.frames);
+ if(ref)
+ ref = lv2_atom_forge_write(forge, &ev->body, sizeof(LV2_Atom) + ev->body.size);
+ }
+ }
+
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame[2]);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame[1]);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame[0]);
+ else
+ lv2_atom_sequence_clear(handle->notify);
+
+ if(!has_midi) // don't send anything
+ lv2_atom_sequence_clear(handle->notify);
+
+ handle->frame += nsamples;
+}
+
+static void
+cleanup(LV2_Handle instance)
+{
+ handle_t *handle = (handle_t *)instance;
+
+ free(handle);
+}
+
+static LV2_State_Status
+_state_save(LV2_Handle instance, LV2_State_Store_Function store,
+ LV2_State_Handle state, uint32_t flags,
+ const LV2_Feature *const *features)
+{
+ handle_t *handle = instance;
+
+ return props_save(&handle->props, store, state, flags, features);
+}
+
+static LV2_State_Status
+_state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
+ LV2_State_Handle state, uint32_t flags,
+ const LV2_Feature *const *features)
+{
+ handle_t *handle = instance;
+
+ return props_restore(&handle->props, retrieve, state, flags, features);
+}
+
+static const LV2_State_Interface state_iface = {
+ .save = _state_save,
+ .restore = _state_restore
+};
+
+static const void*
+extension_data(const char* uri)
+{
+ if(!strcmp(uri, LV2_STATE__interface))
+ return &state_iface;
+
+ return NULL;
+}
+
+const LV2_Descriptor midi_inspector = {
+ .URI = SHERLOCK_MIDI_INSPECTOR_URI,
+ .instantiate = instantiate,
+ .connect_port = connect_port,
+ .activate = NULL,
+ .run = run,
+ .deactivate = NULL,
+ .cleanup = cleanup,
+ .extension_data = extension_data
+};
diff --git a/midi_inspector_nk.c b/midi_inspector_nk.c
new file mode 100644
index 0000000..b1f811b
--- /dev/null
+++ b/midi_inspector_nk.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2015-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 <inttypes.h>
+
+#include <sherlock.h>
+#include <sherlock_nk.h>
+#include <encoder.h>
+
+typedef struct _midi_msg_t midi_msg_t;
+
+struct _midi_msg_t {
+ uint8_t type;
+ const char *key;
+};
+
+#define COMMANDS_NUM 18
+static const midi_msg_t commands [COMMANDS_NUM] = {
+ { LV2_MIDI_MSG_NOTE_OFF , "NoteOff" },
+ { LV2_MIDI_MSG_NOTE_ON , "NoteOn" },
+ { LV2_MIDI_MSG_NOTE_PRESSURE , "NotePressure" },
+ { LV2_MIDI_MSG_CONTROLLER , "Controller" },
+ { LV2_MIDI_MSG_PGM_CHANGE , "ProgramChange" },
+ { LV2_MIDI_MSG_CHANNEL_PRESSURE , "ChannelPressure" },
+ { LV2_MIDI_MSG_BENDER , "Bender" },
+ { LV2_MIDI_MSG_SYSTEM_EXCLUSIVE , "SystemExclusive" },
+ { LV2_MIDI_MSG_MTC_QUARTER , "QuarterFrame" },
+ { LV2_MIDI_MSG_SONG_POS , "SongPosition" },
+ { LV2_MIDI_MSG_SONG_SELECT , "SongSelect" },
+ { LV2_MIDI_MSG_TUNE_REQUEST , "TuneRequest" },
+ { LV2_MIDI_MSG_CLOCK , "Clock" },
+ { LV2_MIDI_MSG_START , "Start" },
+ { LV2_MIDI_MSG_CONTINUE , "Continue" },
+ { LV2_MIDI_MSG_STOP , "Stop" },
+ { LV2_MIDI_MSG_ACTIVE_SENSE , "ActiveSense" },
+ { LV2_MIDI_MSG_RESET , "Reset" },
+};
+
+#define CONTROLLERS_NUM 72
+static const midi_msg_t controllers [CONTROLLERS_NUM] = {
+ { LV2_MIDI_CTL_MSB_BANK , "BankSelection_MSB" },
+ { LV2_MIDI_CTL_MSB_MODWHEEL , "Modulation_MSB" },
+ { LV2_MIDI_CTL_MSB_BREATH , "Breath_MSB" },
+ { LV2_MIDI_CTL_MSB_FOOT , "Foot_MSB" },
+ { LV2_MIDI_CTL_MSB_PORTAMENTO_TIME , "PortamentoTime_MSB" },
+ { LV2_MIDI_CTL_MSB_DATA_ENTRY , "DataEntry_MSB" },
+ { LV2_MIDI_CTL_MSB_MAIN_VOLUME , "MainVolume_MSB" },
+ { LV2_MIDI_CTL_MSB_BALANCE , "Balance_MSB" },
+ { LV2_MIDI_CTL_MSB_PAN , "Panpot_MSB" },
+ { LV2_MIDI_CTL_MSB_EXPRESSION , "Expression_MSB" },
+ { LV2_MIDI_CTL_MSB_EFFECT1 , "Effect1_MSB" },
+ { LV2_MIDI_CTL_MSB_EFFECT2 , "Effect2_MSB" },
+ { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 , "GeneralPurpose1_MSB" },
+ { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 , "GeneralPurpose2_MSB" },
+ { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 , "GeneralPurpose3_MSB" },
+ { LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 , "GeneralPurpose4_MSB" },
+
+ { LV2_MIDI_CTL_LSB_BANK , "BankSelection_LSB" },
+ { LV2_MIDI_CTL_LSB_MODWHEEL , "Modulation_LSB" },
+ { LV2_MIDI_CTL_LSB_BREATH , "Breath_LSB" },
+ { LV2_MIDI_CTL_LSB_FOOT , "Foot_LSB" },
+ { LV2_MIDI_CTL_LSB_PORTAMENTO_TIME , "PortamentoTime_LSB" },
+ { LV2_MIDI_CTL_LSB_DATA_ENTRY , "DataEntry_LSB" },
+ { LV2_MIDI_CTL_LSB_MAIN_VOLUME , "MainVolume_LSB" },
+ { LV2_MIDI_CTL_LSB_BALANCE , "Balance_LSB" },
+ { LV2_MIDI_CTL_LSB_PAN , "Panpot_LSB" },
+ { LV2_MIDI_CTL_LSB_EXPRESSION , "Expression_LSB" },
+ { LV2_MIDI_CTL_LSB_EFFECT1 , "Effect1_LSB" },
+ { LV2_MIDI_CTL_LSB_EFFECT2 , "Effect2_LSB" },
+ { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 , "GeneralPurpose1_LSB" },
+ { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 , "GeneralPurpose2_LSB" },
+ { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 , "GeneralPurpose3_LSB" },
+ { LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 , "GeneralPurpose4_LSB" },
+
+ { LV2_MIDI_CTL_SUSTAIN , "SustainPedal" },
+ { LV2_MIDI_CTL_PORTAMENTO , "Portamento" },
+ { LV2_MIDI_CTL_SOSTENUTO , "Sostenuto" },
+ { LV2_MIDI_CTL_SOFT_PEDAL , "SoftPedal" },
+ { LV2_MIDI_CTL_LEGATO_FOOTSWITCH , "LegatoFootSwitch" },
+ { LV2_MIDI_CTL_HOLD2 , "Hold2" },
+
+ { LV2_MIDI_CTL_SC1_SOUND_VARIATION , "SC1_SoundVariation" },
+ { LV2_MIDI_CTL_SC2_TIMBRE , "SC2_Timbre" },
+ { LV2_MIDI_CTL_SC3_RELEASE_TIME , "SC3_ReleaseTime" },
+ { LV2_MIDI_CTL_SC4_ATTACK_TIME , "SC4_AttackTime" },
+ { LV2_MIDI_CTL_SC5_BRIGHTNESS , "SC5_Brightness" },
+ { LV2_MIDI_CTL_SC6 , "SC6" },
+ { LV2_MIDI_CTL_SC7 , "SC7" },
+ { LV2_MIDI_CTL_SC8 , "SC8" },
+ { LV2_MIDI_CTL_SC9 , "SC9" },
+ { LV2_MIDI_CTL_SC10 , "SC10" },
+
+ { LV2_MIDI_CTL_GENERAL_PURPOSE5 , "GeneralPurpose5" },
+ { LV2_MIDI_CTL_GENERAL_PURPOSE6 , "GeneralPurpose6" },
+ { LV2_MIDI_CTL_GENERAL_PURPOSE7 , "GeneralPurpose7" },
+ { LV2_MIDI_CTL_GENERAL_PURPOSE8 , "GeneralPurpose8" },
+ { LV2_MIDI_CTL_PORTAMENTO_CONTROL , "PortamentoControl" },
+
+ { LV2_MIDI_CTL_E1_REVERB_DEPTH , "E1_ReverbDepth" },
+ { LV2_MIDI_CTL_E2_TREMOLO_DEPTH , "E2_TremoloDepth" },
+ { LV2_MIDI_CTL_E3_CHORUS_DEPTH , "E3_ChorusDepth" },
+ { LV2_MIDI_CTL_E4_DETUNE_DEPTH , "E4_DetuneDepth" },
+ { LV2_MIDI_CTL_E5_PHASER_DEPTH , "E5_PhaserDepth" },
+
+ { LV2_MIDI_CTL_DATA_INCREMENT , "DataIncrement" },
+ { LV2_MIDI_CTL_DATA_DECREMENT , "DataDecrement" },
+
+ { LV2_MIDI_CTL_NRPN_LSB , "NRPN_LSB" },
+ { LV2_MIDI_CTL_NRPN_MSB , "NRPN_MSB" },
+
+ { LV2_MIDI_CTL_RPN_LSB , "RPN_LSB" },
+ { LV2_MIDI_CTL_RPN_MSB , "RPN_MSB" },
+
+ { LV2_MIDI_CTL_ALL_SOUNDS_OFF , "AllSoundsOff" },
+ { LV2_MIDI_CTL_RESET_CONTROLLERS , "ResetControllers" },
+ { LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH , "LocalControlSwitch" },
+ { LV2_MIDI_CTL_ALL_NOTES_OFF , "AllNotesOff" },
+ { LV2_MIDI_CTL_OMNI_OFF , "OmniOff" },
+ { LV2_MIDI_CTL_OMNI_ON , "OmniOn" },
+ { LV2_MIDI_CTL_MONO1 , "Mono1" },
+ { LV2_MIDI_CTL_MONO2 , "Mono2" },
+};
+
+#define TIMECODES_NUM 8
+static const midi_msg_t timecodes [TIMECODES_NUM] = {
+ { 0 , "FrameNumber_LSB" },
+ { 1 , "FrameNumber_MSB" },
+ { 2 , "Second_LSB" },
+ { 3 , "Second_MSB" },
+ { 4 , "Minute_LSB" },
+ { 5 , "Minute_MSB" },
+ { 6 , "Hour_LSB" },
+ { 7 , "RateAndHour_MSB" },
+};
+
+static int
+_cmp_search(const void *itm1, const void *itm2)
+{
+ const midi_msg_t *msg1 = itm1;
+ const midi_msg_t *msg2 = itm2;
+
+ if(msg1->type < msg2->type)
+ return -1;
+ else if(msg1->type > msg2->type)
+ return 1;
+
+ return 0;
+}
+
+static inline const midi_msg_t *
+_search_command(uint8_t type)
+{
+ return bsearch(&type, commands, COMMANDS_NUM, sizeof(midi_msg_t), _cmp_search);
+}
+
+static inline const midi_msg_t *
+_search_controller(uint8_t type)
+{
+ return bsearch(&type, controllers, CONTROLLERS_NUM, sizeof(midi_msg_t), _cmp_search);
+}
+
+static inline const midi_msg_t *
+_search_timecode(uint8_t type)
+{
+ return bsearch(&type, timecodes, TIMECODES_NUM, sizeof(midi_msg_t), _cmp_search);
+}
+
+static const char *keys [12] = {
+ "C", "C#",
+ "D", "D#",
+ "E",
+ "F", "F#",
+ "G", "G#",
+ "A", "A#",
+ "B"
+};
+
+static inline const char *
+_note(uint8_t val, int8_t *octave)
+{
+ *octave = val / 12 - 1;
+
+ return keys[val % 12];
+}
+
+static inline void
+_shadow(struct nk_context *ctx, bool *shadow)
+{
+ if(*shadow)
+ {
+ struct nk_style *style = &ctx->style;
+ const struct nk_vec2 group_padding = style->window.group_padding;
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
+
+ struct nk_rect b = nk_widget_bounds(ctx);
+ b.x -= group_padding.x;
+ b.w *= 10;
+ b.w += 8*group_padding.x;
+ nk_fill_rect(canvas, b, 0.f, nk_rgb(0x28, 0x28, 0x28));
+ }
+
+ *shadow = !*shadow;
+}
+
+void
+_midi_inspector_expose(struct nk_context *ctx, struct nk_rect wbounds, void *data)
+{
+ plughandle_t *handle = data;
+
+ handle->dy = 20.f * _get_scale(handle);
+ const float widget_h = handle->dy;
+ struct nk_style *style = &ctx->style;
+ const struct nk_vec2 window_padding = style->window.padding;
+ const struct nk_vec2 group_padding = style->window.group_padding;
+
+ if(nk_begin(ctx, "Window", wbounds, NK_WINDOW_NO_SCROLLBAR))
+ {
+ nk_window_set_bounds(ctx, wbounds);
+ struct nk_panel *panel = nk_window_get_panel(ctx);
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);
+
+ const float body_h = panel->bounds.h - 4*window_padding.y - 2*widget_h;
+ nk_layout_row_dynamic(ctx, body_h, 1);
+ nk_flags flags = NK_WINDOW_BORDER;
+ if(handle->state.follow)
+ flags |= NK_WINDOW_NO_SCROLLBAR;
+ struct nk_list_view lview;
+ if(nk_list_view_begin(ctx, &lview, "Events", flags, widget_h, NK_MIN(handle->n_item, MAX_LINES)))
+ {
+ if(handle->state.follow)
+ {
+ lview.end = NK_MAX(handle->n_item, 0);
+ lview.begin = NK_MAX(lview.end - lview.count, 0);
+ }
+ handle->shadow = lview.begin % 2 == 0;
+ for(int l = lview.begin; (l < lview.end) && (l < handle->n_item); l++)
+ {
+ item_t *itm = handle->items[l];
+
+ switch(itm->type)
+ {
+ case ITEM_TYPE_NONE:
+ {
+ // skip, was sysex payload
+ } break;
+ case ITEM_TYPE_FRAME:
+ {
+ nk_layout_row_dynamic(ctx, widget_h, 3);
+ {
+ struct nk_rect b = nk_widget_bounds(ctx);
+ b.x -= group_padding.x;
+ b.w *= 3;
+ b.w += 4*group_padding.x;
+ nk_fill_rect(canvas, b, 0.f, nk_rgb(0x18, 0x18, 0x18));
+ }
+
+ nk_labelf_colored(ctx, NK_TEXT_LEFT, orange, "@%"PRIi64, itm->frame.offset);
+ nk_labelf_colored(ctx, NK_TEXT_CENTERED, green, "-%"PRIu32"-", itm->frame.counter);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, violet, "%"PRIi32, itm->frame.nsamples);
+ } break;
+
+ case ITEM_TYPE_EVENT:
+ {
+ LV2_Atom_Event *ev = &itm->event.ev;
+ const LV2_Atom *body = &ev->body;
+ const int64_t frames = ev->time.frames;
+ const uint8_t *msg = LV2_ATOM_BODY_CONST(body);
+ const uint8_t cmd = (msg[0] & 0xf0) == 0xf0
+ ? msg[0]
+ : msg[0] & 0xf0;
+
+ const midi_msg_t *command_msg = _search_command(cmd);
+ const char *command_str = command_msg
+ ? command_msg->key
+ : "Unknown";
+
+ char tmp [16];
+ nk_layout_row_begin(ctx, NK_DYNAMIC, widget_h, 7);
+ {
+ nk_layout_row_push(ctx, 0.1);
+ _shadow(ctx, &handle->shadow);
+ nk_labelf_colored(ctx, NK_TEXT_LEFT, yellow, "+%04"PRIi64, frames);
+
+ nk_layout_row_push(ctx, 0.2);
+ const unsigned rem = body->size;
+ const unsigned to = rem >= 4 ? 4 : rem % 4;
+ for(unsigned i=0, ptr=0; i<to; i++, ptr+=3)
+ sprintf(&tmp[ptr], "%02"PRIX8" ", msg[i]);
+ tmp[to*3 - 1] = '\0';
+ nk_label_colored(ctx, tmp, NK_TEXT_LEFT, white);
+
+ nk_layout_row_push(ctx, 0.2);
+ nk_label_colored(ctx, command_str, NK_TEXT_LEFT, magenta);
+
+ switch(cmd)
+ {
+ case LV2_MIDI_MSG_NOTE_OFF:
+ // fall-through
+ case LV2_MIDI_MSG_NOTE_ON:
+ // fall-through
+ case LV2_MIDI_MSG_NOTE_PRESSURE:
+ {
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "Ch:%02"PRIu8,
+ (msg[0] & 0x0f) + 1);
+
+ nk_layout_row_push(ctx, 0.2);
+ int8_t octave;
+ const char *key = _note(msg[1], &octave);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%s%+"PRIi8, key, octave);
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu8, msg[2]);
+ } break;
+ case LV2_MIDI_MSG_CONTROLLER:
+ {
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "Ch:%02"PRIu8,
+ (msg[0] & 0x0f) + 1);
+
+ const midi_msg_t *controller_msg = _search_controller(msg[1]);
+ const char *controller_str = controller_msg
+ ? controller_msg->key
+ : "Unknown";
+ nk_layout_row_push(ctx, 0.2);
+ nk_label_colored(ctx, controller_str, NK_TEXT_RIGHT, white);
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu8, msg[2]);
+ } break;
+ case LV2_MIDI_MSG_PGM_CHANGE:
+ // fall-through
+ case LV2_MIDI_MSG_CHANNEL_PRESSURE:
+ {
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "Ch:%02"PRIu8,
+ (msg[0] & 0x0f) + 1);
+
+ nk_layout_row_push(ctx, 0.2);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu8, msg[1]);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ } break;
+ case LV2_MIDI_MSG_BENDER:
+ {
+ const int16_t bender = (((int16_t)msg[2] << 7) | msg[1]) - 0x2000;
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "Ch:%02"PRIu8,
+ (msg[0] & 0x0f) + 1);
+
+ nk_layout_row_push(ctx, 0.2);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIi16, bender);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ } break;
+ case LV2_MIDI_MSG_MTC_QUARTER:
+ {
+ const uint8_t msg_type = msg[1] >> 4;
+ const uint8_t msg_val = msg[1] & 0xf;
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ const midi_msg_t *timecode_msg = _search_timecode(msg_type);
+ const char *timecode_str = timecode_msg
+ ? timecode_msg->key
+ : "Unknown";
+ nk_layout_row_push(ctx, 0.2);
+ nk_label_colored(ctx, timecode_str, NK_TEXT_RIGHT, white);
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu8, msg_val);
+ } break;
+ case LV2_MIDI_MSG_SONG_POS:
+ {
+ const int16_t song_pos= (((int16_t)msg[2] << 7) | msg[1]);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.2);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu16, song_pos);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ } break;
+ case LV2_MIDI_MSG_SONG_SELECT:
+ {
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.2);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, white, "%"PRIu8, msg[1]);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ } break;
+ case LV2_MIDI_MSG_SYSTEM_EXCLUSIVE:
+ // fall-throuh
+ case LV2_MIDI_MSG_TUNE_REQUEST:
+ // fall-throuh
+ case LV2_MIDI_MSG_CLOCK:
+ // fall-throuh
+ case LV2_MIDI_MSG_START:
+ // fall-throuh
+ case LV2_MIDI_MSG_CONTINUE:
+ // fall-throuh
+ case LV2_MIDI_MSG_STOP:
+ // fall-throuh
+ case LV2_MIDI_MSG_ACTIVE_SENSE:
+ // fall-throuh
+ case LV2_MIDI_MSG_RESET:
+ {
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.2);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ } break;
+ }
+
+ nk_layout_row_push(ctx, 0.1);
+ nk_labelf_colored(ctx, NK_TEXT_RIGHT, blue, "%"PRIu32, body->size);
+ }
+ nk_layout_row_end(ctx);
+
+ for(unsigned j=4; j<body->size; j+=4)
+ {
+ nk_layout_row_begin(ctx, NK_DYNAMIC, widget_h, 7);
+ {
+ nk_layout_row_push(ctx, 0.1);
+ _shadow(ctx, &handle->shadow);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.2);
+ const unsigned rem = body->size - j;
+ const unsigned to = rem >= 4 ? 4 : rem % 4;
+ for(unsigned i=0, ptr=0; i<to; i++, ptr+=3)
+ sprintf(&tmp[ptr], "%02"PRIX8" ", msg[j+i]);
+ tmp[to*3 - 1] = '\0';
+ nk_label_colored(ctx, tmp, NK_TEXT_LEFT, white);
+
+ nk_layout_row_push(ctx, 0.2);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.2);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+
+ nk_layout_row_push(ctx, 0.1);
+ _empty(ctx);
+ }
+ }
+ } break;
+ }
+ }
+
+ nk_list_view_end(&lview);
+ }
+
+ nk_layout_row_dynamic(ctx, widget_h, 3);
+ {
+ if(nk_checkbox_label(ctx, "overwrite", &handle->state.overwrite))
+ _toggle(handle, handle->urid.overwrite, handle->state.overwrite, true);
+ if(nk_checkbox_label(ctx, "block", &handle->state.block))
+ _toggle(handle, handle->urid.block, handle->state.block, true);
+ if(nk_checkbox_label(ctx, "follow", &handle->state.follow))
+ _toggle(handle, handle->urid.follow, handle->state.follow, true);
+ }
+
+ const bool max_reached = handle->n_item >= MAX_LINES;
+ nk_layout_row_dynamic(ctx, widget_h, 2);
+ if(nk_button_symbol_label(ctx,
+ max_reached ? NK_SYMBOL_TRIANGLE_RIGHT: NK_SYMBOL_NONE,
+ "clear", NK_TEXT_LEFT))
+ {
+ _clear(handle);
+ }
+ nk_label(ctx, "Sherlock.lv2: "SHERLOCK_VERSION, NK_TEXT_RIGHT);
+ }
+ nk_end(ctx);
+}
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 936be6a..936be6a 100644
--- a/nk_pugl.h
+++ b/nk_pugl/nk_pugl.h
diff --git a/nuklear/.gitattributes b/nuklear/.gitattributes
new file mode 100644
index 0000000..5a5328c
--- /dev/null
+++ b/nuklear/.gitattributes
@@ -0,0 +1,3 @@
+# Github language settings
+*.h linguist-language=c
+*.c linguist-language=c
diff --git a/nuklear/.gitignore b/nuklear/.gitignore
new file mode 100644
index 0000000..a9f3b63
--- /dev/null
+++ b/nuklear/.gitignore
@@ -0,0 +1,2 @@
+demo/*/*.exe
+demo/*/*.obj
diff --git a/nuklear/.travis.yml b/nuklear/.travis.yml
new file mode 100644
index 0000000..7df45b3
--- /dev/null
+++ b/nuklear/.travis.yml
@@ -0,0 +1,16 @@
+language: c
+
+os:
+ - linux
+ - osx
+
+compiler:
+ - gcc
+ - clang
+
+before_install:
+ - if [ $TRAVIS_OS_NAME == linux ]; then sudo add-apt-repository -y ppa:pyglfw/pyglfw && sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends libglfw3 libglfw3-dev libglew-dev; fi
+ - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install glfw3 && brew install glew; fi
+
+script:
+ - make -C demo/glfw_opengl3
diff --git a/nuklear/CHANGELOG.md b/nuklear/CHANGELOG.md
new file mode 100644
index 0000000..17f1858
--- /dev/null
+++ b/nuklear/CHANGELOG.md
@@ -0,0 +1,190 @@
+# Changelog
+- 2016/12/03 (1.191)- Fixed wrapped text with no seperator and C89 error
+- 2016/12/03 (1.19) - Changed text wrapping to process words not characters
+- 2016/11/22 (1.184)- Fixed window minimized closing bug
+- 2016/11/19 (1.184)- Fixed abstract combo box closing behavior
+- 2016/11/19 (1.184)- Fixed tooltip flickering
+- 2016/11/19 (1.183)- Fixed memory leak caused by popup repeated closing
+- 2016/11/18 (1.182)- Fixed memory leak caused by popup panel allocation
+- 2016/11/10 (1.181)- Fixed some warnings and C++ error
+- 2016/11/10 (1.180)- Added additional `nk_button` versions which allows to directly
+ pass in a style struct to change buttons visual.
+- 2016/11/10 (1.180)- Added additional 'nk_tree' versions to support external state
+ storage. Just like last the `nk_group` commit the main
+ advantage is that you optionally can minimize nuklears runtime
+ memory consumption or handle hash collisions.
+- 2016/11/09 (1.180)- Added additional `nk_group` version to support external scrollbar
+ offset storage. Main advantage is that you can externalize
+ the memory management for the offset. It could also be helpful
+ if you have a hash collision in `nk_group_begin` but really
+ want the name. In addition I added `nk_list_view` which allows
+ to draw big lists inside a group without actually having to
+ commit the whole list to nuklear (issue #269).
+- 2016/10/30 (1.171)- Fixed clipping rectangle bug inside `nk_draw_list`
+- 2016/10/29 (1.170)- Pulled `nk_panel` memory management into nuklear and out of
+ the hands of the user. From now on users don't have to care
+ about panels unless they care about some information. If you
+ still need the panel just call `nk_window_get_panel`.
+- 2016/10/21 (1.160)- Changed widget border drawing to stroked rectangle from filled
+ rectangle for less overdraw and widget background transparency.
+- 2016/10/18 (1.160)- Added `nk_edit_focus` for manually edit widget focus control
+- 2016/09/29 (1.157)- Fixed deduction of basic type in non `<stdint.h>` compilation
+- 2016/09/29 (1.156)- Fixed edit widget UTF-8 text cursor drawing bug
+- 2016/09/28 (1.156)- Fixed edit widget UTF-8 text appending/inserting/removing
+- 2016/09/28 (1.156)- Fixed drawing bug inside edit widgets which offset all text
+ text in every edit widget if one of them is scrolled.
+- 2016/09/28 (1.155)- Fixed small bug in edit widgets if not active. The wrong
+ text length is passed. It should have been in bytes but
+ was passed as glyphes.
+- 2016/09/20 (1.154)- Fixed color button size calculation
+- 2016/09/20 (1.153)- Fixed some `nk_vsnprintf` behavior bugs and removed
+ `<stdio.h>` again from `NK_INCLUDE_STANDARD_VARARGS`.
+- 2016/09/18 (1.152)- C89 does not support vsnprintf only C99 and newer as well
+ as C++11 and newer. In addition to use vsnprintf you have
+ to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`
+ is not enough. That behavior is now fixed. By default if
+ both varargs as well as stdio is selected I try to use
+ vsnprintf if not possible I will revert to vsprintf. If
+ varargs but not stdio was defined I will use my own function.
+- 2016/09/15 (1.151)- Fixed panel `close` behavior for deeper panel levels
+- 2016/09/15 (1.151)- Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`
+- 2016/09/13 (1.15) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,
+ and contextual which prevented closing in y-direction if
+ popup did not reach max height.
+ In addition the height parameter was changed into vec2
+ for width and height to have more control over the popup size.
+- 2016/09/13 (1.15) - Cleaned up and extended type selection
+- 2016/09/13 (1.141)- Fixed slider behavior hopefully for the last time. This time
+ all calculation are correct so no more hackery.
+- 2016/09/13 (1.141)- Internal change to divide window/panel flags into panel flags and types.
+ Suprisinly spend years in C and still happened to confuse types
+ with flags. Probably something to take note.
+- 2016/09/08 (1.14)- Added additional helper function to make it easier to just
+ take the produced buffers from `nk_convert` and unplug the
+ iteration process from `nk_context`. So now you can
+ just use the vertex,element and command buffer + two pointer
+ inside the command buffer retrieved by calls `nk__draw_begin`
+ and `nk__draw_end` and macro `nk_draw_foreach_bounded`.
+- 2016/09/08 (1.14)- Added additional asserts to make sure every `nk_xxx_begin` call
+ for windows, popups, combobox, menu and contextual is guarded by
+ `if` condition and does not produce false drawing output.
+- 2016/09/08 (1.14)- Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`
+ to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and
+ `NK_SYMBOL_RECT_OUTLINE`.
+- 2016/09/08 (1.14)- Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`
+ to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and
+ `NK_SYMBOL_CIRCLE_OUTLINE`.
+- 2016/09/08 (1.14)- Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`
+ is not defined by supporting the biggest compiler GCC, clang and MSVC.
+- 2016/09/07 (1.133)- Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error
+- 2016/09/04 (1.132)- Fixed wrong combobox height calculation
+- 2016/09/03 (1.131)- Fixed gaps inside combo boxes in OpenGL
+- 2016/09/02 (1.13) - Changed nuklear to not have any default vertex layout and
+ instead made it user provided. The range of types to convert
+ to is quite limited at the moment, but I would be more than
+ happy to accept PRs to add additional.
+- 2016/08/30 (1.12) - Removed unused variables
+- 2016/08/30 (1.12) - Fixed C++ build errors
+- 2016/08/30 (1.12) - Removed mouse dragging from SDL demo since it does not work correctly
+- 2016/08/30 (1.12) - Tweaked some default styling variables
+- 2016/08/30 (1.12) - Hopefully fixed drawing bug in slider, in general I would
+ refrain from using slider with a big number of steps.
+- 2016/08/30 (1.12) - Fixed close and minimize button which would fire even if the
+ window was in Read Only Mode.
+- 2016/08/30 (1.12) - Fixed popup panel padding handling which was previously just
+ a hack for combo box and menu.
+- 2016/08/30 (1.12) - Removed `NK_WINDOW_DYNAMIC` flag from public API since
+ it is bugged and causes issues in window selection.
+- 2016/08/30 (1.12) - Removed scaler size. The size of the scaler is now
+ determined by the scrollbar size
+- 2016/08/30 (1.12) - Fixed some drawing bugs caused by changes from 1.11
+- 2016/08/30 (1.12) - Fixed overlapping minimized window selection
+- 2016/08/30 (1.11) - Removed some internal complexity and overly complex code
+ handling panel padding and panel border.
+- 2016/08/29 (1.10) - Added additional height parameter to `nk_combobox_xxx`
+- 2016/08/29 (1.10) - Fixed drawing bug in dynamic popups
+- 2016/08/29 (1.10) - Added experimental mouse scrolling to popups, menus and comboboxes
+- 2016/08/26 (1.10) - Added window name string prepresentation to account for
+ hash collisions. Currently limited to NK_WINDOW_MAX_NAME
+ which in term can be redefined if not big enough.
+- 2016/08/26 (1.10) - Added stacks for temporary style/UI changes in code
+- 2016/08/25 (1.10) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'
+ to account for key press and release happening in one frame.
+- 2016/08/25 (1.10) - Added additional nk_edit flag to directly jump to the end on activate
+- 2016/08/17 (1.096)- Removed invalid check for value zero in nk_propertyx
+- 2016/08/16 (1.095)- Fixed ROM mode for deeper levels of popup windows parents.
+- 2016/08/15 (1.094)- Editbox are now still active if enter was pressed with flag
+ `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep
+ typing after commiting.
+- 2016/08/15 (1.094)- Removed redundant code
+- 2016/08/15 (1.094)- Fixed negative numbers in `nk_strtoi` and remove unused variable
+- 2016/08/15 (1.093)- Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background
+ window only as selected by hovering and not by clicking.
+- 2016/08/14 (1.092)- Fixed a bug in font atlas which caused wrong loading
+ of glyphes for font with multiple ranges.
+- 2016/08/12 (1.091)- Added additional function to check if window is currently
+ hidden and therefore not visible.
+- 2016/08/12 (1.091)- nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`
+ instead of the old flag `NK_WINDOW_HIDDEN`
+- 2016/08/09 (1.09) - Added additional double version to nk_property and changed
+ the underlying implementation to not cast to float and instead
+ work directly on the given values.
+- 2016/08/09 (1.08) - Added additional define to overwrite library internal
+ floating pointer number to string conversion for additional
+ precision.
+- 2016/08/09 (1.08) - Added additional define to overwrite library internal
+ string to floating point number conversion for additional
+ precision.
+- 2016/08/08 (1.072)- Fixed compiling error without define NK_INCLUDE_FIXED_TYPE
+- 2016/08/08 (1.071)- Fixed possible floating point error inside `nk_widget` leading
+ to wrong wiget width calculation which results in widgets falsly
+ becomming tagged as not inside window and cannot be accessed.
+- 2016/08/08 (1.07) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and
+ closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown
+ by using `nk_window_show` and closed by either clicking the close
+ icon in a window or by calling `nk_window_close`. Only closed
+ windows get removed at the end of the frame while hidden windows
+ remain.
+- 2016/08/08 (1.06) - Added `nk_edit_string_zero_terminated` as a second option to
+ `nk_edit_string` which takes, edits and outputs a '\0' terminated string.
+- 2016/08/08 (1.054)- Fixed scrollbar auto hiding behavior
+- 2016/08/08 (1.053)- Fixed wrong panel padding selection in `nk_layout_widget_space`
+- 2016/08/07 (1.052)- Fixed old bug in dynamic immediate mode layout API, calculating
+ wrong item spacing and panel width.
+- 2016/08/07 (1.051)- Hopefully finally fixed combobox popup drawing bug
+- 2016/08/07 (1.05) - Split varargs away from NK_INCLUDE_STANDARD_IO into own
+ define NK_INCLUDE_STANDARD_VARARGS to allow more fine
+ grained controlled over library includes.
+- 2016/08/06 (1.045)- Changed memset calls to NK_MEMSET
+- 2016/08/04 (1.044)- Fixed fast window scaling behavior
+- 2016/08/04 (1.043)- Fixed window scaling, movement bug which appears if you
+ move/scale a window and another window is behind it.
+ If you are fast enough then the window behind gets activated
+ and the operation is blocked. I now require activating
+ by hovering only if mouse is not pressed.
+- 2016/08/04 (1.042)- Fixed changing fonts
+- 2016/08/03 (1.041)- Fixed `NK_WINDOW_BACKGROUND` behavior
+- 2016/08/03 (1.04) - Added color parameter to `nk_draw_image`
+- 2016/08/03 (1.04) - Added additional window padding style attributes for
+ sub windows (combo, menu, ...)
+- 2016/08/03 (1.04) - Added functions to show/hide software cursor
+- 2016/08/03 (1.04) - Added `NK_WINDOW_BACKGROUND` flag to force a window
+ to be always in the background of the screen
+- 2016/08/03 (1.032)- Removed invalid assert macro for NK_RGB color picker
+- 2016/08/01 (1.031)- Added helper macros into header include guard
+- 2016/07/29 (1.03) - Moved the window/table pool into the header part to
+ simplify memory management by removing the need to
+ allocate the pool.
+- 2016/07/29 (1.03) - Added auto scrollbar hiding window flag which if enabled
+ will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT
+ seconds without window interaction. To make it work
+ you have to also set a delta time inside the `nk_context`.
+- 2016/07/25 (1.02) - Fixed small panel and panel border drawing bugs
+- 2016/07/15 (1.01) - Added software cursor to `nk_style` and `nk_context`
+- 2016/07/15 (1.01) - Added const correctness to `nk_buffer_push' data argument
+- 2016/07/15 (1.01) - Removed internal font baking API and simplified
+ font atlas memory management by converting pointer
+ arrays for fonts and font configurations to lists.
+- 2016/07/15 (1.01) - Changed button API to use context dependend button
+ behavior instead of passing it for every function call.
+
diff --git a/nuklear/Readme.md b/nuklear/Readme.md
new file mode 100644
index 0000000..29d56d3
--- /dev/null
+++ b/nuklear/Readme.md
@@ -0,0 +1,111 @@
+[![Build Status](https://travis-ci.org/vurtun/nuklear.svg)](https://travis-ci.org/vurtun/nuklear)
+
+# Nuklear
+This is a minimal state immediate mode graphical user interface toolkit
+written in ANSI C and licensed under public domain. It was designed as a simple
+embeddable user interface for application and does not have any dependencies,
+a default renderbackend or OS window and input handling but instead provides a very modular
+library approach by using simple input state for input and draw
+commands describing primitive shapes as output. So instead of providing a
+layered library that tries to abstract over a number of platform and
+render backends it only focuses on the actual UI.
+
+## Features
+- Immediate mode graphical user interface toolkit
+- Single header library
+- Written in C89 (ANSI C)
+- Small codebase (~15kLOC)
+- Focus on portability, efficiency and simplicity
+- No dependencies (not even the standard library if not wanted)
+- Fully skinnable and customizable
+- Low memory footprint with total memory control if needed or wanted
+- UTF-8 support
+- No global or hidden state
+- Customizable library modules (you can compile and use only what you need)
+- Optional font baker and vertex buffer output
+
+## Building
+This library is self contained in one single header file and can be used either
+in header only mode or in implementation mode. The header only mode is used
+by default when included and allows including this header in other headers
+and does not contain the actual implementation.
+
+The implementation mode requires to define the preprocessor macro
+`NK_IMPLEMENTATION` in *one* .c/.cpp file before `#include`ing this file, e.g.:
+```c
+#define NK_IMPLEMENTATION
+#include "nuklear.h"
+```
+IMPORTANT: Every time you include "nuklear.h" you have to define the same optional flags.
+This is very important not doing it either leads to compiler errors or even worse stack corruptions.
+
+## Gallery
+![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
+![screen](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)
+![screen2](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)
+![node](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)
+![skinning](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)
+![gamepad](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)
+
+## Example
+```c
+/* init gui state */
+struct nk_context ctx;
+nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
+
+enum {EASY, HARD};
+int op = EASY;
+float value = 0.6f;
+int i = 20;
+
+if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
+ /* fixed widget pixel width */
+ nk_layout_row_static(&ctx, 30, 80, 1);
+ if (nk_button_label(&ctx, "button")) {
+ /* event handling */
+ }
+
+ /* fixed widget window ratio width */
+ nk_layout_row_dynamic(&ctx, 30, 2);
+ if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
+
+ /* custom widget pixel width */
+ nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
+ {
+ nk_layout_row_push(&ctx, 50);
+ nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
+ nk_layout_row_push(&ctx, 110);
+ nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
+ }
+ nk_layout_row_end(&ctx);
+}
+nk_end(&ctx);
+```
+![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
+
+## Bindings:
+Java: https://github.com/glegris/nuklear4j
+Golang: https://github.com/golang-ui/nuklear
+Rust: https://github.com/snuk182/nuklear-rust
+
+## Credits:
+Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
+
+
+Embeds `stb_texedit`, `stb_truetype` and `stb_rectpack` by Sean Barret (public domain)
+Embeds `ProggyClean.ttf` font by Tristan Grimmer (MIT license).
+
+
+Big thank you to Omar Cornut (ocornut@github) for his [imgui](https://github.com/ocornut/imgui) library and
+giving me the inspiration for this library, Casey Muratori for handmade hero
+and his original immediate mode graphical user interface idea and Sean
+Barret for his amazing single header [libraries](https://github.com/nothings/stb) which restored my faith
+in libraries and brought me to create some of my own.
+
+## License:
+This software is dual-licensed to the public domain and under the following
+license: you are granted a perpetual, irrevocable license to copy, modify,
+publish and distribute this file as you see fit.
+
diff --git a/nuklear/demo/calculator.c b/nuklear/demo/calculator.c
new file mode 100644
index 0000000..b871301
--- /dev/null
+++ b/nuklear/demo/calculator.c
@@ -0,0 +1,64 @@
+/* nuklear - v1.00 - public domain */
+static void
+calculator(struct nk_context *ctx)
+{
+ if (nk_begin(ctx, "Calculator", nk_rect(10, 10, 180, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
+ {
+ static int set = 0, prev = 0, op = 0;
+ static const char numbers[] = "789456123";
+ static const char ops[] = "+-*/";
+ static double a = 0, b = 0;
+ static double *current = &a;
+
+ size_t i = 0;
+ int solve = 0;
+ {int len; char buffer[256];
+ nk_layout_row_dynamic(ctx, 35, 1);
+ len = snprintf(buffer, 256, "%.2f", *current);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_float);
+ buffer[len] = 0;
+ *current = atof(buffer);}
+
+ nk_layout_row_dynamic(ctx, 35, 4);
+ for (i = 0; i < 16; ++i) {
+ if (i >= 12 && i < 15) {
+ if (i > 12) continue;
+ if (nk_button_label(ctx, "C")) {
+ a = b = op = 0; current = &a; set = 0;
+ } if (nk_button_label(ctx, "0")) {
+ *current = *current*10.0f; set = 0;
+ } if (nk_button_label(ctx, "=")) {
+ solve = 1; prev = op; op = 0;
+ }
+ } else if (((i+1) % 4)) {
+ if (nk_button_text(ctx, &numbers[(i/4)*3+i%4], 1)) {
+ *current = *current * 10.0f + numbers[(i/4)*3+i%4] - '0';
+ set = 0;
+ }
+ } else if (nk_button_text(ctx, &ops[i/4], 1)) {
+ if (!set) {
+ if (current != &b) {
+ current = &b;
+ } else {
+ prev = op;
+ solve = 1;
+ }
+ }
+ op = ops[i/4];
+ set = 1;
+ }
+ }
+ if (solve) {
+ if (prev == '+') a = a + b;
+ if (prev == '-') a = a - b;
+ if (prev == '*') a = a * b;
+ if (prev == '/') a = a / b;
+ current = &a;
+ if (set) current = &b;
+ b = 0; set = 0;
+ }
+ }
+ nk_end(ctx);
+}
+
diff --git a/nuklear/demo/d3d11/build.bat b/nuklear/demo/d3d11/build.bat
new file mode 100644
index 0000000..31bd0e0
--- /dev/null
+++ b/nuklear/demo/d3d11/build.bat
@@ -0,0 +1,9 @@
+@echo off
+
+rem This will use VS2015 for compiler
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+fxc.exe /nologo /T vs_4_0_level_9_0 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d11_vertex_shader.h /Vn nk_d3d11_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl
+fxc.exe /nologo /T ps_4_0_level_9_0 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d11_pixel_shader.h /Vn nk_d3d11_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl
+
+cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib d3d11.lib /link /incremental:no
diff --git a/nuklear/demo/d3d11/main.c b/nuklear/demo/d3d11/main.c
new file mode 100644
index 0000000..bc0dc64
--- /dev/null
+++ b/nuklear/demo/d3d11/main.c
@@ -0,0 +1,278 @@
+/* nuklear - v1.17 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d11.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_INDEX_BUFFER 128 * 1024
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D11_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d11.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #define UNUSED(a) (void)a
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+ #define MAX(a,b) ((a) < (b) ? (b) : (a))
+ #define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static IDXGISwapChain *swap_chain;
+static ID3D11Device *device;
+static ID3D11DeviceContext *context;
+static ID3D11RenderTargetView* rt_view;
+
+static void
+set_swap_chain_size(int width, int height)
+{
+ ID3D11Texture2D *back_buffer;
+ D3D11_RENDER_TARGET_VIEW_DESC desc;
+ HRESULT hr;
+
+ if (rt_view)
+ ID3D11RenderTargetView_Release(rt_view);
+
+ ID3D11DeviceContext_OMSetRenderTargets(context, 0, NULL, NULL);
+
+ hr = IDXGISwapChain_ResizeBuffers(swap_chain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
+ {
+ /* to recover from this, you'll need to recreate device and all the resources */
+ MessageBoxW(NULL, L"DXGI device is removed or reset!", L"Error", 0);
+ exit(0);
+ }
+ assert(SUCCEEDED(hr));
+
+ memset(&desc, 0, sizeof(desc));
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+
+ hr = IDXGISwapChain_GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, &back_buffer);
+ assert(SUCCEEDED(hr));
+
+ hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)back_buffer, &desc, &rt_view);
+ assert(SUCCEEDED(hr));
+
+ ID3D11Texture2D_Release(back_buffer);
+}
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_SIZE:
+ if (swap_chain)
+ {
+ int width = LOWORD(lparam);
+ int height = HIWORD(lparam);
+ set_swap_chain_size(width, height);
+ nk_d3d11_resize(context, width, height);
+ }
+ break;
+ }
+
+ if (nk_d3d11_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ WNDCLASSW wc;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ int running = 1;
+ HRESULT hr;
+ D3D_FEATURE_LEVEL feature_level;
+ DXGI_SWAP_CHAIN_DESC swap_chain_desc;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+
+ /* D3D11 setup */
+ memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
+ swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
+ swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
+ swap_chain_desc.SampleDesc.Count = 1;
+ swap_chain_desc.SampleDesc.Quality = 0;
+ swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swap_chain_desc.BufferCount = 1;
+ swap_chain_desc.OutputWindow = wnd;
+ swap_chain_desc.Windowed = TRUE;
+ swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ swap_chain_desc.Flags = 0;
+ if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE,
+ NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,
+ &swap_chain, &device, &feature_level, &context)))
+ {
+ /* if hardware device fails, then try WARP high-performance
+ software rasterizer, this is useful for RDP sessions */
+ hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP,
+ NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,
+ &swap_chain, &device, &feature_level, &context);
+ assert(SUCCEEDED(hr));
+ }
+ set_swap_chain_size(WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ /* GUI */
+ ctx = nk_d3d11_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_d3d11_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_d3d11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 22, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ {/* Draw */
+ float bg[4];
+ nk_color_fv(bg, background);
+ ID3D11DeviceContext_ClearRenderTargetView(context, rt_view, bg);
+ ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rt_view, NULL);
+ nk_d3d11_render(context, NK_ANTI_ALIASING_ON);
+ hr = IDXGISwapChain_Present(swap_chain, 1, 0);
+ if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {
+ /* to recover from this, you'll need to recreate device and all the resources */
+ MessageBoxW(NULL, L"D3D11 device is lost or removed!", L"Error", 0);
+ break;
+ } else if (hr == DXGI_STATUS_OCCLUDED) {
+ /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+ Sleep(10);
+ }
+ assert(SUCCEEDED(hr));}
+ }
+
+ ID3D11DeviceContext_ClearState(context);
+ nk_d3d11_shutdown();
+ ID3D11ShaderResourceView_Release(rt_view);
+ ID3D11DeviceContext_Release(context);
+ ID3D11Device_Release(device);
+ IDXGISwapChain_Release(swap_chain);
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
diff --git a/nuklear/demo/d3d11/nuklear_d3d11.h b/nuklear/demo/d3d11/nuklear_d3d11.h
new file mode 100644
index 0000000..efddf0d
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11.h
@@ -0,0 +1,617 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D11_H_
+#define NK_D3D11_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct ID3D11Device ID3D11Device;
+typedef struct ID3D11DeviceContext ID3D11DeviceContext;
+
+NK_API struct nk_context *nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer);
+NK_API void nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_d3d11_font_stash_end(void);
+NK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing);
+NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);
+NK_API void nk_d3d11_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D11_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d11.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <float.h>
+#include <assert.h>
+
+#include "nuklear_d3d11_vertex_shader.h"
+#include "nuklear_d3d11_pixel_shader.h"
+
+struct nk_d3d11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct
+{
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_buffer cmds;
+
+ struct nk_draw_null_texture null;
+ unsigned int max_vertex_buffer;
+ unsigned int max_index_buffer;
+
+ D3D11_VIEWPORT viewport;
+ ID3D11Device *device;
+ ID3D11RasterizerState *rasterizer_state;
+ ID3D11VertexShader *vertex_shader;
+ ID3D11InputLayout *input_layout;
+ ID3D11Buffer *const_buffer;
+ ID3D11PixelShader *pixel_shader;
+ ID3D11BlendState *blend_state;
+ ID3D11Buffer *index_buffer;
+ ID3D11Buffer *vertex_buffer;
+ ID3D11ShaderResourceView *font_texture_view;
+ ID3D11SamplerState *sampler_state;
+} d3d11;
+
+NK_API void
+nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing AA)
+{
+ const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ const UINT stride = sizeof(struct nk_d3d11_vertex);
+ const UINT offset = 0;
+
+ ID3D11DeviceContext_IASetInputLayout(context, d3d11.input_layout);
+ ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &d3d11.vertex_buffer, &stride, &offset);
+ ID3D11DeviceContext_IASetIndexBuffer(context, d3d11.index_buffer, DXGI_FORMAT_R16_UINT, 0);
+ ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+ ID3D11DeviceContext_VSSetShader(context, d3d11.vertex_shader, NULL, 0);
+ ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &d3d11.const_buffer);
+
+ ID3D11DeviceContext_PSSetShader(context, d3d11.pixel_shader, NULL, 0);
+ ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &d3d11.sampler_state);
+
+ ID3D11DeviceContext_OMSetBlendState(context, d3d11.blend_state, blend_factor, 0xffffffff);
+ ID3D11DeviceContext_RSSetState(context, d3d11.rasterizer_state);
+ ID3D11DeviceContext_RSSetViewports(context, 1, &d3d11.viewport);
+
+ /* Convert from command queue into draw list and draw to screen */
+ {/* load draw vertices & elements directly into vertex + element buffer */
+ D3D11_MAPPED_SUBRESOURCE vertices;
+ D3D11_MAPPED_SUBRESOURCE indices;
+ const struct nk_draw_command *cmd;
+ UINT offset = 0;
+ HRESULT hr;
+
+ hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertices);
+ NK_ASSERT(SUCCEEDED(hr));
+ hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);
+ NK_ASSERT(SUCCEEDED(hr));
+
+ {/* fill converting configuration */
+ struct nk_convert_config config;
+ NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ memset(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_d3d11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_d3d11_vertex);
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.null = d3d11.null;
+
+ {/* setup buffers to load vertices and elements */
+ struct nk_buffer vbuf, ibuf;
+ nk_buffer_init_fixed(&vbuf, vertices.pData, (size_t)d3d11.max_vertex_buffer);
+ nk_buffer_init_fixed(&ibuf, indices.pData, (size_t)d3d11.max_index_buffer);
+ nk_convert(&d3d11.ctx, &d3d11.cmds, &vbuf, &ibuf, &config);}
+ }
+
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.vertex_buffer, 0);
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.index_buffer, 0);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, &d3d11.ctx, &d3d11.cmds)
+ {
+ D3D11_RECT scissor;
+ ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;
+ if (!cmd->elem_count) continue;
+
+ scissor.left = (LONG)cmd->clip_rect.x;
+ scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
+ scissor.top = (LONG)cmd->clip_rect.y;
+ scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
+
+ ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &texture_view);
+ ID3D11DeviceContext_RSSetScissorRects(context, 1, &scissor);
+ ID3D11DeviceContext_DrawIndexed(context, (UINT)cmd->elem_count, offset, 0);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&d3d11.ctx);}
+}
+
+static void
+nk_d3d11_get_projection_matrix(int width, int height, float *result)
+{
+ const float L = 0.0f;
+ const float R = (float)width;
+ const float T = 0.0f;
+ const float B = (float)height;
+ float matrix[4][4] =
+ {
+ { 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
+ };
+ memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height)
+{
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ if (SUCCEEDED(ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)))
+ {
+ nk_d3d11_get_projection_matrix(width, height, (float *)mapped.pData);
+ ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.const_buffer, 0);
+
+ d3d11.viewport.Width = (float)width;
+ d3d11.viewport.Height = (float)height;
+ }
+}
+
+NK_API int
+nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&d3d11.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&d3d11.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&d3d11.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&d3d11.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&d3d11.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&d3d11.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&d3d11.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&d3d11.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&d3d11.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+nk_d3d11_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ (void)usr;
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ {
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem)
+ {
+ SIZE_T size = GlobalSize(mem) - 1;
+ if (size)
+ {
+ LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+ if (wstr)
+ {
+ int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
+ if (utf8size)
+ {
+ char* utf8 = (char*)malloc(utf8size);
+ if (utf8)
+ {
+ WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ }
+ }
+ GlobalUnlock(mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+static void
+nk_d3d11_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ (void)usr;
+ if (OpenClipboard(NULL))
+ {
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (wsize)
+ {
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (mem)
+ {
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (wstr)
+ {
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+ SetClipboardData(CF_UNICODETEXT, mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+NK_API struct nk_context*
+nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer)
+{
+ HRESULT hr;
+ d3d11.max_vertex_buffer = max_vertex_buffer;
+ d3d11.max_index_buffer = max_index_buffer;
+ d3d11.device = device;
+ ID3D11Device_AddRef(device);
+
+ nk_init_default(&d3d11.ctx, 0);
+ d3d11.ctx.clip.copy = nk_d3d11_clipbard_copy;
+ d3d11.ctx.clip.paste = nk_d3d11_clipbard_paste;
+ d3d11.ctx.clip.userdata = nk_handle_ptr(0);
+
+ nk_buffer_init_default(&d3d11.cmds);
+
+ {/* rasterizer state */
+ D3D11_RASTERIZER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.FrontCounterClockwise = FALSE;
+ desc.DepthBias = 0;
+ desc.DepthBiasClamp = 0;
+ desc.SlopeScaledDepthBias = 0.0f;
+ desc.DepthClipEnable = TRUE;
+ desc.ScissorEnable = TRUE;
+ desc.MultisampleEnable = FALSE;
+ desc.AntialiasedLineEnable = FALSE;
+ hr = ID3D11Device_CreateRasterizerState(device,&desc, &d3d11.rasterizer_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* vertex shader */
+ {hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* input layout */
+ {const D3D11_INPUT_ELEMENT_DESC layout[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(struct nk_d3d11_vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ hr = ID3D11Device_CreateInputLayout(device,layout, ARRAYSIZE(layout), nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), &d3d11.input_layout);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* constant buffer */
+ {float matrix[4*4];
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.ByteWidth = sizeof(matrix);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+
+ {D3D11_SUBRESOURCE_DATA data;
+ data.pSysMem = matrix;
+ data.SysMemPitch = 0;
+ data.SysMemSlicePitch = 0;
+
+ nk_d3d11_get_projection_matrix(width, height, matrix);
+ hr = ID3D11Device_CreateBuffer(device, &desc, &data, &d3d11.const_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}}
+
+ /* pixel shader */
+ {hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ {/* blend state */
+ D3D11_BLEND_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.AlphaToCoverageEnable = FALSE;
+ desc.RenderTarget[0].BlendEnable = TRUE;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ hr = ID3D11Device_CreateBlendState(device, &desc, &d3d11.blend_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* vertex buffer */
+ {D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = max_vertex_buffer;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.vertex_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* index buffer */
+ {D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = max_index_buffer;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.index_buffer);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* sampler state */
+ {D3D11_SAMPLER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.MipLODBias = 0.0f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.0f;
+ desc.MaxLOD = FLT_MAX;
+ hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11.sampler_state);
+ NK_ASSERT(SUCCEEDED(hr));}
+
+ /* viewport */
+ {d3d11.viewport.TopLeftX = 0.0f;
+ d3d11.viewport.TopLeftY = 0.0f;
+ d3d11.viewport.Width = (float)width;
+ d3d11.viewport.Height = (float)height;
+ d3d11.viewport.MinDepth = 0.0f;
+ d3d11.viewport.MaxDepth = 1.0f;}
+ return &d3d11.ctx;
+}
+
+NK_API void
+nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&d3d11.atlas);
+ nk_font_atlas_begin(&d3d11.atlas);
+ *atlas = &d3d11.atlas;
+}
+
+NK_API void
+nk_d3d11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&d3d11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+
+ /* upload font to texture and create texture view */
+ {ID3D11Texture2D *font_texture;
+ HRESULT hr;
+
+ D3D11_TEXTURE2D_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.Width = (UINT)w;
+ desc.Height = (UINT)h;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ {D3D11_SUBRESOURCE_DATA data;
+ data.pSysMem = image;
+ data.SysMemPitch = (UINT)(w * 4);
+ data.SysMemSlicePitch = 0;
+ hr = ID3D11Device_CreateTexture2D(d3d11.device, &desc, &data, &font_texture);
+ assert(SUCCEEDED(hr));}
+
+ {D3D11_SHADER_RESOURCE_VIEW_DESC srv;
+ memset(&srv, 0, sizeof(srv));
+ srv.Format = desc.Format;
+ srv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv.Texture2D.MipLevels = 1;
+ srv.Texture2D.MostDetailedMip = 0;
+ hr = ID3D11Device_CreateShaderResourceView(d3d11.device, (ID3D11Resource *)font_texture, &srv, &d3d11.font_texture_view);
+ assert(SUCCEEDED(hr));}
+ ID3D11Texture2D_Release(font_texture);}
+
+ nk_font_atlas_end(&d3d11.atlas, nk_handle_ptr(d3d11.font_texture_view), &d3d11.null);
+ if (d3d11.atlas.default_font)
+ nk_style_set_font(&d3d11.ctx, &d3d11.atlas.default_font->handle);
+}
+
+NK_API
+void nk_d3d11_shutdown(void)
+{
+ nk_font_atlas_clear(&d3d11.atlas);
+ nk_buffer_free(&d3d11.cmds);
+ nk_free(&d3d11.ctx);
+
+ ID3D11SamplerState_Release(d3d11.sampler_state);
+ ID3D11ShaderResourceView_Release(d3d11.font_texture_view);
+ ID3D11Buffer_Release(d3d11.vertex_buffer);
+ ID3D11Buffer_Release(d3d11.index_buffer);
+ ID3D11BlendState_Release(d3d11.blend_state);
+ ID3D11PixelShader_Release(d3d11.pixel_shader);
+ ID3D11Buffer_Release(d3d11.const_buffer);
+ ID3D11VertexShader_Release(d3d11.vertex_shader);
+ ID3D11InputLayout_Release(d3d11.input_layout);
+ ID3D11RasterizerState_Release(d3d11.rasterizer_state);
+ ID3D11Device_Release(d3d11.device);
+}
+
+#endif
+
diff --git a/nuklear/demo/d3d11/nuklear_d3d11.hlsl b/nuklear/demo/d3d11/nuklear_d3d11.hlsl
new file mode 100644
index 0000000..a932dca
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11.hlsl
@@ -0,0 +1,36 @@
+//
+cbuffer buffer0 : register(b0)
+{
+ float4x4 ProjectionMatrix;
+};
+
+sampler sampler0 : register(s0);
+Texture2D<float4> texture0 : register(t0);
+
+struct VS_INPUT
+{
+ float2 pos : POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+struct PS_INPUT
+{
+ float4 pos : SV_POSITION;
+ float4 col : COLOR0;
+ float2 uv : TEXCOORD0;
+};
+
+PS_INPUT vs(VS_INPUT input)
+{
+ PS_INPUT output;
+ output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
+ output.col = input.col;
+ output.uv = input.uv;
+ return output;
+}
+
+float4 ps(PS_INPUT input) : SV_Target
+{
+ return input.col * texture0.Sample(sampler0, input.uv);
+}
diff --git a/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h b/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h
new file mode 100644
index 0000000..1447559
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11_pixel_shader.h
@@ -0,0 +1,179 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION 0 xyzw 0 POS float
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target 0 xyzw 0 TARGET float xyzw
+//
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler Source Resource
+// -------------- --------------- ----------------
+// s0 s0 t0
+//
+//
+// Level9 shader bytecode:
+//
+ ps_2_0
+ dcl t0
+ dcl t1.xy
+ dcl_2d s0
+ texld r0, t1, s0
+ mul r0, r0, t0
+ mov oC0, r0
+
+// approximately 3 instruction slots used (1 texture, 2 arithmetic)
+//
+// Sampler/Resource to DX9 shader sampler mappings:
+//
+// Target Sampler Source Sampler Source Resource
+// -------------- --------------- ----------------
+// s0 s0 t0
+//
+//
+// XNA shader bytecode:
+//
+ ps_2_0
+ dcl t0
+ dcl t1.xy
+ dcl_2d s0
+ texld r0, r2, s0
+ mul oC0, r0, r1
+
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xyzw
+dcl_input_ps linear v2.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v2.xyxx, t0.xyzw, s0
+mul o0.xyzw, r0.xyzw, v1.xyzw
+ret
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d11_pixel_shader[] =
+{
+ 68, 88, 66, 67, 249, 46,
+ 26, 75, 111, 182, 161, 241,
+ 199, 179, 191, 89, 44, 229,
+ 245, 103, 1, 0, 0, 0,
+ 124, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 176, 0, 0, 0, 56, 1,
+ 0, 0, 212, 1, 0, 0,
+ 72, 2, 0, 0, 88, 78,
+ 65, 83, 116, 0, 0, 0,
+ 116, 0, 0, 0, 0, 2,
+ 255, 255, 76, 0, 0, 0,
+ 40, 0, 0, 0, 0, 0,
+ 40, 0, 0, 0, 40, 0,
+ 0, 0, 40, 0, 1, 0,
+ 36, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 0, 2,
+ 255, 255, 31, 0, 0, 2,
+ 0, 0, 0, 128, 0, 0,
+ 15, 176, 31, 0, 0, 2,
+ 0, 0, 0, 128, 1, 0,
+ 3, 176, 31, 0, 0, 2,
+ 0, 0, 0, 144, 0, 8,
+ 15, 160, 66, 0, 0, 3,
+ 0, 0, 15, 128, 2, 0,
+ 228, 128, 0, 8, 228, 160,
+ 5, 0, 0, 3, 0, 8,
+ 15, 128, 0, 0, 228, 128,
+ 1, 0, 228, 128, 255, 255,
+ 0, 0, 65, 111, 110, 57,
+ 128, 0, 0, 0, 128, 0,
+ 0, 0, 0, 2, 255, 255,
+ 88, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 40, 0,
+ 0, 0, 40, 0, 0, 0,
+ 40, 0, 1, 0, 36, 0,
+ 0, 0, 40, 0, 0, 0,
+ 0, 0, 0, 2, 255, 255,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 0, 0, 15, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 1, 0, 3, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 144, 0, 8, 15, 160,
+ 66, 0, 0, 3, 0, 0,
+ 15, 128, 1, 0, 228, 176,
+ 0, 8, 228, 160, 5, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 228, 128, 0, 0,
+ 228, 176, 1, 0, 0, 2,
+ 0, 8, 15, 128, 0, 0,
+ 228, 128, 255, 255, 0, 0,
+ 83, 72, 68, 82, 148, 0,
+ 0, 0, 64, 0, 0, 0,
+ 37, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 0, 4, 0, 112, 16, 0,
+ 0, 0, 0, 0, 85, 85,
+ 0, 0, 98, 16, 0, 3,
+ 242, 16, 16, 0, 1, 0,
+ 0, 0, 98, 16, 0, 3,
+ 50, 16, 16, 0, 2, 0,
+ 0, 0, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 69, 0,
+ 0, 9, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 16,
+ 16, 0, 2, 0, 0, 0,
+ 70, 126, 16, 0, 0, 0,
+ 0, 0, 0, 96, 16, 0,
+ 0, 0, 0, 0, 56, 0,
+ 0, 7, 242, 32, 16, 0,
+ 0, 0, 0, 0, 70, 14,
+ 16, 0, 0, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 62, 0, 0, 1,
+ 73, 83, 71, 78, 108, 0,
+ 0, 0, 3, 0, 0, 0,
+ 8, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 15, 15, 0, 0, 98, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 0, 0, 0,
+ 3, 3, 0, 0, 83, 86,
+ 95, 80, 79, 83, 73, 84,
+ 73, 79, 78, 0, 67, 79,
+ 76, 79, 82, 0, 84, 69,
+ 88, 67, 79, 79, 82, 68,
+ 0, 171, 79, 83, 71, 78,
+ 44, 0, 0, 0, 1, 0,
+ 0, 0, 8, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 83, 86, 95, 84, 97, 114,
+ 103, 101, 116, 0, 171, 171
+};
diff --git a/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h b/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h
new file mode 100644
index 0000000..770d2dd
--- /dev/null
+++ b/nuklear/demo/d3d11/nuklear_d3d11_vertex_shader.h
@@ -0,0 +1,350 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION 0 xy 0 NONE float xy
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION 0 xyzw 0 POS float xyzw
+// COLOR 0 xyzw 1 NONE float xyzw
+// TEXCOORD 0 xy 2 NONE float xy
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c1 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg Constant Description
+// ---------- --------------------------------------------------
+// c0 Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+ vs_2_0
+ def c5, 0, 1, 0, 0
+ dcl_texcoord v0
+ dcl_texcoord1 v1
+ dcl_texcoord2 v2
+ mul r0, v0.x, c1
+ mad r0, c2, v0.y, r0
+ mov r1.xy, c5
+ mad r0, c3, r1.x, r0
+ mad r0, c4, r1.y, r0
+ mul r1.xy, r0.w, c0
+ add oPos.xy, r0, r1
+ mov oPos.zw, r0
+ mov oT0, v1
+ mov oT1.xy, v2
+
+// approximately 10 instruction slots used
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// XNA Prepass shader bytecode:
+//
+ vs_2_0
+ def c4, 0, 1, 0, 0
+ dcl_texcoord v0
+ mul r1, r0.x, c0
+ mad r0, c1, r0.y, r1
+ mov r1.xy, c4
+ mad r0, c2, r1.x, r0
+ mad r0, c3, r1.y, r0
+ mov oPos, r0
+
+// approximately 6 instruction slots used
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer Start Reg # of Regs Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c0 cb0 0 4 ( FLT, FLT, FLT, FLT)
+//
+//
+// XNA shader bytecode:
+//
+ vs_2_0
+ def c4, 0, 1, 0, 0
+ dcl_texcoord v0
+ dcl_texcoord1 v1
+ dcl_texcoord2 v2
+ mov oT0, r1
+ mov oT1.xy, r2
+ mul r1, r0.x, c0
+ mad r0, c1, r0.y, r1
+ mov r1.xy, c4
+ mad r0, c2, r1.x, r0
+ mad r0, c3, r1.y, r0
+ mov oPos, r0
+
+// approximately 8 instruction slots used
+vs_4_0
+dcl_constantbuffer cb0[4], immediateIndexed
+dcl_input v0.xy
+dcl_input v1.xyzw
+dcl_input v2.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xyzw
+dcl_output o2.xy
+dcl_temps 1
+mul r0.xyzw, v0.xxxx, cb0[0].xyzw
+mad r0.xyzw, cb0[1].xyzw, v0.yyyy, r0.xyzw
+mad r0.xyzw, cb0[2].xyzw, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzw
+mad o0.xyzw, cb0[3].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000), r0.xyzw
+mov o1.xyzw, v1.xyzw
+mov o2.xy, v2.xyxx
+ret
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d11_vertex_shader[] =
+{
+ 68, 88, 66, 67, 215, 245,
+ 86, 155, 188, 117, 37, 118,
+ 193, 207, 209, 90, 160, 153,
+ 246, 188, 1, 0, 0, 0,
+ 72, 5, 0, 0, 6, 0,
+ 0, 0, 56, 0, 0, 0,
+ 48, 1, 0, 0, 248, 1,
+ 0, 0, 20, 3, 0, 0,
+ 100, 4, 0, 0, 212, 4,
+ 0, 0, 88, 78, 65, 83,
+ 240, 0, 0, 0, 240, 0,
+ 0, 0, 0, 2, 254, 255,
+ 192, 0, 0, 0, 48, 0,
+ 0, 0, 1, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 48, 0, 0, 0, 36, 0,
+ 0, 0, 48, 0, 0, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2,
+ 254, 255, 81, 0, 0, 5,
+ 4, 0, 15, 160, 0, 0,
+ 0, 0, 0, 0, 128, 63,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 31, 0, 0, 2,
+ 5, 0, 0, 128, 0, 0,
+ 15, 144, 31, 0, 0, 2,
+ 5, 0, 1, 128, 1, 0,
+ 15, 144, 31, 0, 0, 2,
+ 5, 0, 2, 128, 2, 0,
+ 15, 144, 1, 0, 0, 2,
+ 0, 0, 15, 224, 1, 0,
+ 228, 128, 1, 0, 0, 2,
+ 1, 0, 3, 224, 2, 0,
+ 228, 128, 5, 0, 0, 3,
+ 1, 0, 15, 128, 0, 0,
+ 0, 128, 0, 0, 228, 160,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 1, 0, 228, 160,
+ 0, 0, 85, 128, 1, 0,
+ 228, 128, 1, 0, 0, 2,
+ 1, 0, 3, 128, 4, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 2, 0,
+ 228, 160, 1, 0, 0, 128,
+ 0, 0, 228, 128, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 3, 0, 228, 160, 1, 0,
+ 85, 128, 0, 0, 228, 128,
+ 1, 0, 0, 2, 0, 0,
+ 15, 192, 0, 0, 228, 128,
+ 255, 255, 0, 0, 88, 78,
+ 65, 80, 192, 0, 0, 0,
+ 192, 0, 0, 0, 0, 2,
+ 254, 255, 144, 0, 0, 0,
+ 48, 0, 0, 0, 1, 0,
+ 36, 0, 0, 0, 48, 0,
+ 0, 0, 48, 0, 0, 0,
+ 36, 0, 0, 0, 48, 0,
+ 0, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 2, 254, 255, 81, 0,
+ 0, 5, 4, 0, 15, 160,
+ 0, 0, 0, 0, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 5, 0, 0, 128,
+ 0, 0, 15, 144, 5, 0,
+ 0, 3, 1, 0, 15, 128,
+ 0, 0, 0, 128, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 1, 0,
+ 228, 160, 0, 0, 85, 128,
+ 1, 0, 228, 128, 1, 0,
+ 0, 2, 1, 0, 3, 128,
+ 4, 0, 228, 160, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 2, 0, 228, 160, 1, 0,
+ 0, 128, 0, 0, 228, 128,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 3, 0, 228, 160,
+ 1, 0, 85, 128, 0, 0,
+ 228, 128, 1, 0, 0, 2,
+ 0, 0, 15, 192, 0, 0,
+ 228, 128, 255, 255, 0, 0,
+ 65, 111, 110, 57, 20, 1,
+ 0, 0, 20, 1, 0, 0,
+ 0, 2, 254, 255, 224, 0,
+ 0, 0, 52, 0, 0, 0,
+ 1, 0, 36, 0, 0, 0,
+ 48, 0, 0, 0, 48, 0,
+ 0, 0, 36, 0, 1, 0,
+ 48, 0, 0, 0, 0, 0,
+ 4, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 2, 254, 255, 81, 0,
+ 0, 5, 5, 0, 15, 160,
+ 0, 0, 0, 0, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 5, 0, 0, 128,
+ 0, 0, 15, 144, 31, 0,
+ 0, 2, 5, 0, 1, 128,
+ 1, 0, 15, 144, 31, 0,
+ 0, 2, 5, 0, 2, 128,
+ 2, 0, 15, 144, 5, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 0, 144, 1, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 128, 2, 0,
+ 228, 160, 0, 0, 85, 144,
+ 0, 0, 228, 128, 1, 0,
+ 0, 2, 1, 0, 3, 128,
+ 5, 0, 228, 160, 4, 0,
+ 0, 4, 0, 0, 15, 128,
+ 3, 0, 228, 160, 1, 0,
+ 0, 128, 0, 0, 228, 128,
+ 4, 0, 0, 4, 0, 0,
+ 15, 128, 4, 0, 228, 160,
+ 1, 0, 85, 128, 0, 0,
+ 228, 128, 5, 0, 0, 3,
+ 1, 0, 3, 128, 0, 0,
+ 255, 128, 0, 0, 228, 160,
+ 2, 0, 0, 3, 0, 0,
+ 3, 192, 0, 0, 228, 128,
+ 1, 0, 228, 128, 1, 0,
+ 0, 2, 0, 0, 12, 192,
+ 0, 0, 228, 128, 1, 0,
+ 0, 2, 0, 0, 15, 224,
+ 1, 0, 228, 144, 1, 0,
+ 0, 2, 1, 0, 3, 224,
+ 2, 0, 228, 144, 255, 255,
+ 0, 0, 83, 72, 68, 82,
+ 72, 1, 0, 0, 64, 0,
+ 1, 0, 82, 0, 0, 0,
+ 89, 0, 0, 4, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 0, 0, 0, 0, 95, 0,
+ 0, 3, 242, 16, 16, 0,
+ 1, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 2, 0, 0, 0, 103, 0,
+ 0, 4, 242, 32, 16, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 101, 0, 0, 3,
+ 242, 32, 16, 0, 1, 0,
+ 0, 0, 101, 0, 0, 3,
+ 50, 32, 16, 0, 2, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 56, 0,
+ 0, 8, 242, 0, 16, 0,
+ 0, 0, 0, 0, 6, 16,
+ 16, 0, 0, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 50, 0, 0, 10, 242, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 86, 21, 16, 0, 0, 0,
+ 0, 0, 70, 14, 16, 0,
+ 0, 0, 0, 0, 50, 0,
+ 0, 13, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 70, 14, 16, 0, 0, 0,
+ 0, 0, 50, 0, 0, 13,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 70, 142, 32, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 128, 63, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 0, 0, 128, 63, 70, 14,
+ 16, 0, 0, 0, 0, 0,
+ 54, 0, 0, 5, 242, 32,
+ 16, 0, 1, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 50, 32, 16, 0, 2, 0,
+ 0, 0, 70, 16, 16, 0,
+ 2, 0, 0, 0, 62, 0,
+ 0, 1, 73, 83, 71, 78,
+ 104, 0, 0, 0, 3, 0,
+ 0, 0, 8, 0, 0, 0,
+ 80, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 0, 0,
+ 89, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 15, 0, 0,
+ 95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 2, 0,
+ 0, 0, 3, 3, 0, 0,
+ 80, 79, 83, 73, 84, 73,
+ 79, 78, 0, 67, 79, 76,
+ 79, 82, 0, 84, 69, 88,
+ 67, 79, 79, 82, 68, 0,
+ 79, 83, 71, 78, 108, 0,
+ 0, 0, 3, 0, 0, 0,
+ 8, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 92, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 15, 0, 0, 0, 98, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 2, 0, 0, 0,
+ 3, 12, 0, 0, 83, 86,
+ 95, 80, 79, 83, 73, 84,
+ 73, 79, 78, 0, 67, 79,
+ 76, 79, 82, 0, 84, 69,
+ 88, 67, 79, 79, 82, 68,
+ 0, 171
+};
diff --git a/nuklear/demo/gdi/build.bat b/nuklear/demo/gdi/build.bat
new file mode 100644
index 0000000..3884317
--- /dev/null
+++ b/nuklear/demo/gdi/build.bat
@@ -0,0 +1,6 @@
+@echo off
+
+rem This will use VS2015 for compiler
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdi32.lib /link /incremental:no
diff --git a/nuklear/demo/gdi/main.c b/nuklear/demo/gdi/main.c
new file mode 100644
index 0000000..e82cd16
--- /dev/null
+++ b/nuklear/demo/gdi/main.c
@@ -0,0 +1,161 @@
+/* nuklear - v1.17 - public domain */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDI_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_gdi.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ if (nk_gdi_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ GdiFont* font;
+ struct nk_context *ctx;
+
+ WNDCLASSW wc;
+ ATOM atom;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ HDC dc;
+ int running = 1;
+ int needs_refresh = 1;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ atom = RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+ dc = GetDC(wnd);
+
+ /* GUI */
+ font = nk_gdifont_create("Arial", 14);
+ ctx = nk_gdi_init(font, dc, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ if (needs_refresh == 0) {
+ if (GetMessageW(&msg, NULL, 0, 0) <= 0)
+ running = 0;
+ else {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ needs_refresh = 1;
+ } else needs_refresh = 0;
+
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ needs_refresh = 1;
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 22, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ nk_gdi_render(nk_rgb(30,30,30));
+ }
+
+ nk_gdifont_del(font);
+ ReleaseDC(wnd, dc);
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
+
diff --git a/nuklear/demo/gdi/nuklear_gdi.h b/nuklear/demo/gdi/nuklear_gdi.h
new file mode 100644
index 0000000..6d3a84a
--- /dev/null
+++ b/nuklear/demo/gdi/nuklear_gdi.h
@@ -0,0 +1,761 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GDI_H_
+#define NK_GDI_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct GdiFont GdiFont;
+NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);
+NK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_gdi_render(struct nk_color clear);
+NK_API void nk_gdi_shutdown(void);
+
+/* font */
+NK_API GdiFont* nk_gdifont_create(const char *name, int size);
+NK_API void nk_gdifont_del(GdiFont *font);
+NK_API void nk_gdi_set_font(GdiFont *font);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GDI_IMPLEMENTATION
+
+#include <stdlib.h>
+#include <malloc.h>
+
+struct GdiFont {
+ struct nk_user_font nk;
+ int height;
+ HFONT handle;
+ HDC dc;
+};
+
+static struct {
+ HBITMAP bitmap;
+ HDC window_dc;
+ HDC memory_dc;
+ unsigned int width;
+ unsigned int height;
+ struct nk_context ctx;
+} gdi;
+
+static COLORREF
+convert_color(struct nk_color c)
+{
+ return c.r | (c.g << 8) | (c.b << 16);
+}
+
+static void
+nk_gdi_scissor(HDC dc, float x, float y, float w, float h)
+{
+ SelectClipRgn(dc, NULL);
+ IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1));
+}
+
+static void
+nk_gdi_stroke_line(HDC dc, short x0, short y0, short x1,
+ short y1, unsigned int line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ MoveToEx(dc, x0, y0, NULL);
+ LineTo(dc, x1, y1);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ if (r == 0) {
+ Rectangle(dc, x, y, x + w, y + h);
+ } else {
+ RoundRect(dc, x, y, x + w, y + h, r, r);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+
+ if (r == 0) {
+ RECT rect = { x, y, x + w, y + h };
+ SetBkColor(dc, color);
+ ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
+ } else {
+ SetDCPenColor(dc, color);
+ SetDCBrushColor(dc, color);
+ RoundRect(dc, x, y, x + w, y + h, r, r);
+ }
+}
+
+static void
+nk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1,
+ short y1, short x2, short y2, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ };
+
+ SetDCPenColor(dc, color);
+ SetDCBrushColor(dc, color);
+ Polygon(dc, points, 3);
+}
+
+static void
+nk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1,
+ short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ { x0, y0 },
+ };
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ Polyline(dc, points, 4);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_polygon(HDC dc, const struct nk_vec2i *pnts, int count, struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 64
+ POINT points[MAX_POINTS];
+ COLORREF color = convert_color(col);
+ SetDCBrushColor(dc, color);
+ SetDCPenColor(dc, color);
+ for (i = 0; i < count && i < MAX_POINTS; ++i) {
+ points[i].x = pnts[i].x;
+ points[i].y = pnts[i].y;
+ }
+ Polygon(dc, points, i);
+ #undef MAX_POINTS
+}
+
+static void
+nk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i *pnts, int count,
+ unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ if (count > 0) {
+ int i;
+ MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
+ for (i = 1; i < count; ++i)
+ LineTo(dc, pnts[i].x, pnts[i].y);
+ LineTo(dc, pnts[0].x, pnts[0].y);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i *pnts,
+ int count, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ if (count > 0) {
+ int i;
+ MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);
+ for (i = 1; i < count; ++i)
+ LineTo(dc, pnts[i].x, pnts[i].y);
+ }
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ SetDCBrushColor(dc, color);
+ SetDCPenColor(dc, color);
+ Ellipse(dc, x, y, x + w, y + h);
+}
+
+static void
+nk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w,
+ unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ Ellipse(dc, x, y, x + w, y + h);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1,
+ struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+ unsigned short line_thickness, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ POINT p[] = {
+ { p1.x, p1.y },
+ { p2.x, p2.y },
+ { p3.x, p3.y },
+ { p4.x, p4.y },
+ };
+
+ HPEN pen = NULL;
+ if (line_thickness == 1) {
+ SetDCPenColor(dc, color);
+ } else {
+ pen = CreatePen(PS_SOLID, line_thickness, color);
+ SelectObject(dc, pen);
+ }
+
+ SetDCBrushColor(dc, OPAQUE);
+ PolyBezier(dc, p, 4);
+
+ if (pen) {
+ SelectObject(dc, GetStockObject(DC_PEN));
+ DeleteObject(pen);
+ }
+}
+
+static void
+nk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h,
+ const char *text, int len, GdiFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+ int wsize;
+ WCHAR* wstr;
+
+ if(!text || !font || !len) return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ SetBkColor(dc, convert_color(cbg));
+ SetTextColor(dc, convert_color(cfg));
+
+ SelectObject(dc, font->handle);
+ ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL);
+}
+
+static void
+nk_gdi_clear(HDC dc, struct nk_color col)
+{
+ COLORREF color = convert_color(col);
+ RECT rect = { 0, 0, gdi.width, gdi.height };
+ SetBkColor(dc, color);
+
+ ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
+}
+
+static void
+nk_gdi_blit(HDC dc)
+{
+ BitBlt(dc, 0, 0, gdi.width, gdi.height, gdi.memory_dc, 0, 0, SRCCOPY);
+}
+
+GdiFont*
+nk_gdifont_create(const char *name, int size)
+{
+ TEXTMETRICW metric;
+ GdiFont *font = (GdiFont*)calloc(1, sizeof(GdiFont));
+ if (!font)
+ return NULL;
+ font->dc = CreateCompatibleDC(0);
+ font->handle = CreateFont(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);
+ SelectObject(font->dc, font->handle);
+ GetTextMetricsW(font->dc, &metric);
+ font->height = metric.tmHeight;
+ return font;
+}
+
+static float
+nk_gdifont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ GdiFont *font = (GdiFont*)handle.ptr;
+ SIZE size;
+ int wsize;
+ WCHAR* wstr;
+ if (!font || !text)
+ return 0;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size))
+ return (float)size.cx;
+ return -1.0f;
+}
+
+void
+nk_gdifont_del(GdiFont *font)
+{
+ if(!font) return;
+ DeleteObject(font->handle);
+ DeleteDC(font->dc);
+ free(font);
+}
+
+static void
+nk_gdi_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ (void)usr;
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ {
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem)
+ {
+ SIZE_T size = GlobalSize(mem) - 1;
+ if (size)
+ {
+ LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+ if (wstr)
+ {
+ int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
+ if (utf8size)
+ {
+ char* utf8 = (char*)malloc(utf8size);
+ if (utf8)
+ {
+ WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ }
+ }
+ GlobalUnlock(mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+static void
+nk_gdi_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ if (OpenClipboard(NULL))
+ {
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (wsize)
+ {
+ HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (mem)
+ {
+ wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+ if (wstr)
+ {
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+ }
+ }
+ }
+ CloseClipboard();
+ }
+}
+
+NK_API struct nk_context*
+nk_gdi_init(GdiFont *gdifont, HDC window_dc, unsigned int width, unsigned int height)
+{
+ struct nk_user_font *font = &gdifont->nk;
+ font->userdata = nk_handle_ptr(gdifont);
+ font->height = (float)gdifont->height;
+ font->width = nk_gdifont_get_text_width;
+
+ gdi.bitmap = CreateCompatibleBitmap(window_dc, width, height);
+ gdi.window_dc = window_dc;
+ gdi.memory_dc = CreateCompatibleDC(window_dc);
+ gdi.width = width;
+ gdi.height = height;
+ SelectObject(gdi.memory_dc, gdi.bitmap);
+
+ nk_init_default(&gdi.ctx, font);
+ gdi.ctx.clip.copy = nk_gdi_clipbard_copy;
+ gdi.ctx.clip.paste = nk_gdi_clipbard_paste;
+ return &gdi.ctx;
+}
+
+NK_API void
+nk_gdi_set_font(GdiFont *gdifont)
+{
+ struct nk_user_font *font = &gdifont->nk;
+ font->userdata = nk_handle_ptr(gdifont);
+ font->height = (float)gdifont->height;
+ font->width = nk_gdifont_get_text_width;
+ nk_style_set_font(&gdi.ctx, font);
+}
+
+NK_API int
+nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_SIZE:
+ {
+ unsigned width = LOWORD(lparam);
+ unsigned height = LOWORD(lparam);
+ if (width != gdi.width || height != gdi.height)
+ {
+ DeleteObject(gdi.bitmap);
+ gdi.bitmap = CreateCompatibleBitmap(gdi.window_dc, width, height);
+ gdi.width = width;
+ gdi.height = height;
+ SelectObject(gdi.memory_dc, gdi.bitmap);
+ }
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT paint;
+ HDC dc = BeginPaint(wnd, &paint);
+ nk_gdi_blit(dc);
+ EndPaint(wnd, &paint);
+ return 1;
+ }
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&gdi.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&gdi.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&gdi.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&gdi.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&gdi.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&gdi.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&gdi.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&gdi.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&gdi.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&gdi.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&gdi.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+NK_API void
+nk_gdi_shutdown(void)
+{
+ DeleteObject(gdi.memory_dc);
+ DeleteObject(gdi.bitmap);
+ nk_free(&gdi.ctx);
+}
+
+NK_API void
+nk_gdi_render(struct nk_color clear)
+{
+ const struct nk_command *cmd;
+
+ HDC memory_dc = gdi.memory_dc;
+ SelectObject(memory_dc, GetStockObject(DC_PEN));
+ SelectObject(memory_dc, GetStockObject(DC_BRUSH));
+ nk_gdi_clear(memory_dc, clear);
+
+ nk_foreach(cmd, &gdi.ctx)
+ {
+ switch (cmd->type) {
+ case NK_COMMAND_NOP: break;
+ case NK_COMMAND_SCISSOR: {
+ const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+ nk_gdi_scissor(memory_dc, s->x, s->y, s->w, s->h);
+ } break;
+ case NK_COMMAND_LINE: {
+ const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+ nk_gdi_stroke_line(memory_dc, l->begin.x, l->begin.y, l->end.x,
+ l->end.y, l->line_thickness, l->color);
+ } break;
+ case NK_COMMAND_RECT: {
+ const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+ nk_gdi_stroke_rect(memory_dc, r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->line_thickness, r->color);
+ } break;
+ case NK_COMMAND_RECT_FILLED: {
+ const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+ nk_gdi_fill_rect(memory_dc, r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->color);
+ } break;
+ case NK_COMMAND_CIRCLE: {
+ const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+ nk_gdi_stroke_circle(memory_dc, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
+ } break;
+ case NK_COMMAND_CIRCLE_FILLED: {
+ const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+ nk_gdi_fill_circle(memory_dc, c->x, c->y, c->w, c->h, c->color);
+ } break;
+ case NK_COMMAND_TRIANGLE: {
+ const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+ nk_gdi_stroke_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->line_thickness, t->color);
+ } break;
+ case NK_COMMAND_TRIANGLE_FILLED: {
+ const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+ nk_gdi_fill_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->color);
+ } break;
+ case NK_COMMAND_POLYGON: {
+ const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
+ nk_gdi_stroke_polygon(memory_dc, p->points, p->point_count, p->line_thickness,p->color);
+ } break;
+ case NK_COMMAND_POLYGON_FILLED: {
+ const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+ nk_gdi_fill_polygon(memory_dc, p->points, p->point_count, p->color);
+ } break;
+ case NK_COMMAND_POLYLINE: {
+ const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+ nk_gdi_stroke_polyline(memory_dc, p->points, p->point_count, p->line_thickness, p->color);
+ } break;
+ case NK_COMMAND_TEXT: {
+ const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+ nk_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h,
+ (const char*)t->string, t->length,
+ (GdiFont*)t->font->userdata.ptr,
+ t->background, t->foreground);
+ } break;
+ case NK_COMMAND_CURVE: {
+ const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+ nk_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1],
+ q->end, q->line_thickness, q->color);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_IMAGE:
+ case NK_COMMAND_ARC:
+ case NK_COMMAND_ARC_FILLED:
+ default: break;
+ }
+ }
+ nk_gdi_blit(gdi.window_dc);
+ nk_clear(&gdi.ctx);
+}
+
+#endif
+
diff --git a/nuklear/demo/gdip/build.bat b/nuklear/demo/gdip/build.bat
new file mode 100644
index 0000000..28f51a3
--- /dev/null
+++ b/nuklear/demo/gdip/build.bat
@@ -0,0 +1,5 @@
+@echo off
+
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdiplus.lib /link /incremental:no
diff --git a/nuklear/demo/gdip/main.c b/nuklear/demo/gdip/main.c
new file mode 100644
index 0000000..7d623e7
--- /dev/null
+++ b/nuklear/demo/gdip/main.c
@@ -0,0 +1,155 @@
+/* nuklear - v1.17 - public domain */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDIP_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_gdip.h"
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* These are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #define UNUSED(a) (void)a
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+ #define MAX(a,b) ((a) < (b) ? (b) : (a))
+ #define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+ if (nk_gdip_handle_event(wnd, msg, wparam, lparam))
+ return 0;
+ return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{
+ GdipFont* font;
+ struct nk_context *ctx;
+
+ WNDCLASSW wc;
+ RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ DWORD exstyle = WS_EX_APPWINDOW;
+ HWND wnd;
+ int running = 1;
+ int needs_refresh = 1;
+
+ /* Win32 */
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = GetModuleHandleW(0);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpszClassName = L"NuklearWindowClass";
+ RegisterClassW(&wc);
+
+ AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+ wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+ style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, wc.hInstance, NULL);
+
+ /* GUI */
+ ctx = nk_gdip_init(wnd, WINDOW_WIDTH, WINDOW_HEIGHT);
+ font = nk_gdipfont_create("Arial", 12);
+ nk_gdip_set_font(font);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ while (running)
+ {
+ /* Input */
+ MSG msg;
+ nk_input_begin(ctx);
+ if (needs_refresh == 0) {
+ if (GetMessageW(&msg, NULL, 0, 0) <= 0)
+ running = 0;
+ else {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ needs_refresh = 1;
+ } else needs_refresh = 0;
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT)
+ running = 0;
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ needs_refresh = 1;
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 22, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ nk_gdip_render(NK_ANTI_ALIASING_ON, nk_rgb(30,30,30));
+ }
+
+ nk_gdipfont_del(font);
+ nk_gdip_shutdown();
+ UnregisterClassW(wc.lpszClassName, wc.hInstance);
+ return 0;
+}
diff --git a/nuklear/demo/gdip/nuklear_gdip.h b/nuklear/demo/gdip/nuklear_gdip.h
new file mode 100644
index 0000000..66ccc0d
--- /dev/null
+++ b/nuklear/demo/gdip/nuklear_gdip.h
@@ -0,0 +1,1006 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GDIP_H_
+#define NK_GDIP_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* font */
+typedef struct GdipFont GdipFont;
+NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
+NK_API void nk_gdipfont_del(GdipFont *font);
+
+NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height);
+NK_API void nk_gdip_set_font(GdipFont *font);
+NK_API int nk_gdip_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear);
+NK_API void nk_gdip_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GDIP_IMPLEMENTATION
+
+#include <stdlib.h>
+#include <malloc.h>
+
+/* manually declare everything GDI+ needs, because
+ GDI+ headers are not usable from C */
+#define WINGDIPAPI __stdcall
+#define GDIPCONST const
+
+typedef struct GpGraphics GpGraphics;
+typedef struct GpImage GpImage;
+typedef struct GpPen GpPen;
+typedef struct GpBrush GpBrush;
+typedef struct GpStringFormat GpStringFormat;
+typedef struct GpFont GpFont;
+typedef struct GpFontFamily GpFontFamily;
+typedef struct GpFontCollection GpFontCollection;
+
+typedef GpImage GpBitmap;
+typedef GpBrush GpSolidFill;
+
+typedef int Status;
+typedef Status GpStatus;
+
+typedef float REAL;
+typedef DWORD ARGB;
+typedef POINT GpPoint;
+
+typedef enum {
+ TextRenderingHintSystemDefault = 0,
+ TextRenderingHintSingleBitPerPixelGridFit = 1,
+ TextRenderingHintSingleBitPerPixel = 2,
+ TextRenderingHintAntiAliasGridFit = 3,
+ TextRenderingHintAntiAlias = 4,
+ TextRenderingHintClearTypeGridFit = 5
+} TextRenderingHint;
+
+typedef enum {
+ StringFormatFlagsDirectionRightToLeft = 0x00000001,
+ StringFormatFlagsDirectionVertical = 0x00000002,
+ StringFormatFlagsNoFitBlackBox = 0x00000004,
+ StringFormatFlagsDisplayFormatControl = 0x00000020,
+ StringFormatFlagsNoFontFallback = 0x00000400,
+ StringFormatFlagsMeasureTrailingSpaces = 0x00000800,
+ StringFormatFlagsNoWrap = 0x00001000,
+ StringFormatFlagsLineLimit = 0x00002000,
+ StringFormatFlagsNoClip = 0x00004000
+} StringFormatFlags;
+
+typedef enum
+{
+ QualityModeInvalid = -1,
+ QualityModeDefault = 0,
+ QualityModeLow = 1,
+ QualityModeHigh = 2
+} QualityMode;
+
+typedef enum
+{
+ SmoothingModeInvalid = QualityModeInvalid,
+ SmoothingModeDefault = QualityModeDefault,
+ SmoothingModeHighSpeed = QualityModeLow,
+ SmoothingModeHighQuality = QualityModeHigh,
+ SmoothingModeNone,
+ SmoothingModeAntiAlias,
+ SmoothingModeAntiAlias8x4 = SmoothingModeAntiAlias,
+ SmoothingModeAntiAlias8x8
+} SmoothingMode;
+
+typedef enum
+{
+ FontStyleRegular = 0,
+ FontStyleBold = 1,
+ FontStyleItalic = 2,
+ FontStyleBoldItalic = 3,
+ FontStyleUnderline = 4,
+ FontStyleStrikeout = 8
+} FontStyle;
+
+typedef enum {
+ FillModeAlternate,
+ FillModeWinding
+} FillMode;
+
+typedef enum {
+ CombineModeReplace,
+ CombineModeIntersect,
+ CombineModeUnion,
+ CombineModeXor,
+ CombineModeExclude,
+ CombineModeComplement
+} CombineMode;
+
+typedef enum {
+ UnitWorld,
+ UnitDisplay,
+ UnitPixel,
+ UnitPoint,
+ UnitInch,
+ UnitDocument,
+ UnitMillimeter
+} Unit;
+
+typedef struct {
+ FLOAT X;
+ FLOAT Y;
+ FLOAT Width;
+ FLOAT Height;
+} RectF;
+
+typedef enum {
+ DebugEventLevelFatal,
+ DebugEventLevelWarning
+} DebugEventLevel;
+
+typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
+
+typedef struct {
+ UINT32 GdiplusVersion;
+ DebugEventProc DebugEventCallback;
+ BOOL SuppressBackgroundThread;
+ BOOL SuppressExternalCodecs;
+} GdiplusStartupInput;
+
+typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
+typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);
+
+typedef struct {
+ NotificationHookProc NotificationHook;
+ NotificationUnhookProc NotificationUnhook;
+} GdiplusStartupOutput;
+
+/* startup & shutdown */
+
+Status WINAPI GdiplusStartup(
+ OUT ULONG_PTR *token,
+ const GdiplusStartupInput *input,
+ OUT GdiplusStartupOutput *output);
+
+VOID WINAPI GdiplusShutdown(ULONG_PTR token);
+
+/* image */
+
+GpStatus WINGDIPAPI
+GdipCreateBitmapFromGraphics(INT width,
+ INT height,
+ GpGraphics* target,
+ GpBitmap** bitmap);
+
+GpStatus WINGDIPAPI
+GdipDisposeImage(GpImage *image);
+
+GpStatus WINGDIPAPI
+GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics);
+
+/* pen */
+
+GpStatus WINGDIPAPI
+GdipCreatePen1(ARGB color, REAL width, Unit unit, GpPen **pen);
+
+GpStatus WINGDIPAPI
+GdipDeletePen(GpPen *pen);
+
+GpStatus WINGDIPAPI
+GdipSetPenWidth(GpPen *pen, REAL width);
+
+GpStatus WINGDIPAPI
+GdipSetPenColor(GpPen *pen, ARGB argb);
+
+/* brush */
+
+GpStatus WINGDIPAPI
+GdipCreateSolidFill(ARGB color, GpSolidFill **brush);
+
+GpStatus WINGDIPAPI
+GdipDeleteBrush(GpBrush *brush);
+
+GpStatus WINGDIPAPI
+GdipSetSolidFillColor(GpSolidFill *brush, ARGB color);
+
+/* font */
+
+GpStatus WINGDIPAPI
+GdipCreateFont(
+ GDIPCONST GpFontFamily *fontFamily,
+ REAL emSize,
+ INT style,
+ Unit unit,
+ GpFont **font
+);
+
+GpStatus WINGDIPAPI
+GdipDeleteFont(GpFont* font);
+
+GpStatus WINGDIPAPI
+GdipGetFontSize(GpFont *font, REAL *size);
+
+GpStatus WINGDIPAPI
+GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name,
+ GpFontCollection *fontCollection,
+ GpFontFamily **fontFamily);
+
+GpStatus WINGDIPAPI
+GdipDeleteFontFamily(GpFontFamily *fontFamily);
+
+GpStatus WINGDIPAPI
+GdipStringFormatGetGenericTypographic(GpStringFormat **format);
+
+GpStatus WINGDIPAPI
+GdipSetStringFormatFlags(GpStringFormat *format, INT flags);
+
+GpStatus WINGDIPAPI
+GdipDeleteStringFormat(GpStringFormat *format);
+
+/* graphics */
+
+
+GpStatus WINGDIPAPI
+GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics);
+
+GpStatus WINGDIPAPI
+GdipCreateFromHDC(HDC hdc, GpGraphics **graphics);
+
+GpStatus WINGDIPAPI
+GdipDeleteGraphics(GpGraphics *graphics);
+
+GpStatus WINGDIPAPI
+GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode);
+
+GpStatus WINGDIPAPI
+GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
+ INT width, INT height, CombineMode combineMode);
+
+GpStatus WINGDIPAPI
+GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,
+ INT x2, INT y2);
+
+GpStatus WINGDIPAPI
+GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height, REAL startAngle, REAL sweepAngle);
+
+GpStatus WINGDIPAPI
+GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height, REAL startAngle, REAL sweepAngle);
+
+GpStatus WINGDIPAPI
+GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
+ GDIPCONST GpPoint *points, INT count, FillMode fillMode);
+
+GpStatus WINGDIPAPI
+GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points,
+ INT count);
+
+GpStatus WINGDIPAPI
+GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y,
+ INT width, INT height);
+
+GpStatus WINGDIPAPI
+GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,
+ INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);
+
+GpStatus WINGDIPAPI
+GdipDrawString(
+ GpGraphics *graphics,
+ GDIPCONST WCHAR *string,
+ INT length,
+ GDIPCONST GpFont *font,
+ GDIPCONST RectF *layoutRect,
+ GDIPCONST GpStringFormat *stringFormat,
+ GDIPCONST GpBrush *brush
+);
+
+GpStatus WINGDIPAPI
+GdipGraphicsClear(GpGraphics *graphics, ARGB color);
+
+GpStatus WINGDIPAPI
+GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, INT y);
+
+GpStatus WINGDIPAPI
+GdipMeasureString(
+ GpGraphics *graphics,
+ GDIPCONST WCHAR *string,
+ INT length,
+ GDIPCONST GpFont *font,
+ GDIPCONST RectF *layoutRect,
+ GDIPCONST GpStringFormat *stringFormat,
+ RectF *boundingBox,
+ INT *codepointsFitted,
+ INT *linesFilled
+);
+
+GpStatus WINGDIPAPI
+GdipSetTextRenderingHint(GpGraphics *graphics, TextRenderingHint mode);
+
+struct GdipFont
+{
+ struct nk_user_font nk;
+ GpFont* handle;
+};
+
+static struct {
+ ULONG_PTR token;
+
+ GpGraphics *window;
+ GpGraphics *memory;
+ GpImage *bitmap;
+ GpPen *pen;
+ GpSolidFill *brush;
+ GpStringFormat *format;
+
+ struct nk_context ctx;
+} gdip;
+
+static ARGB convert_color(struct nk_color c)
+{
+ return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b;
+}
+
+static void
+nk_gdip_scissor(float x, float y, float w, float h)
+{
+ GdipSetClipRectI(gdip.memory, (INT)x, (INT)y, (INT)(w + 1), (INT)(h + 1), CombineModeReplace);
+}
+
+static void
+nk_gdip_stroke_line(short x0, short y0, short x1,
+ short y1, unsigned int line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawLineI(gdip.memory, gdip.pen, x0, y0, x1, y1);
+}
+
+static void
+nk_gdip_stroke_rect(short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (r == 0) {
+ GdipDrawRectangleI(gdip.memory, gdip.pen, x, y, w, h);
+ } else {
+ INT d = 2 * r;
+ GdipDrawArcI(gdip.memory, gdip.pen, x, y, d, d, 180, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + d, y, x + w - d, y);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + d, x + w, y + h - d);
+ GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x, y + d, x + w, y + h - d);
+ GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90);
+ GdipDrawLineI(gdip.memory, gdip.pen, x + d, y + h, x + w - d, y + h);
+ }
+}
+
+static void
+nk_gdip_fill_rect(short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, struct nk_color col)
+{
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ if (r == 0) {
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);
+ } else {
+ INT d = 2 * r;
+ GdipFillRectangleI(gdip.memory, gdip.brush, x + r, y, w - d, h);
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y + r, w, h - d);
+ GdipFillPieI(gdip.memory, gdip.brush, x, y, d, d, 180, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y, d, d, 270, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y + h - d, d, d, 0, 90);
+ GdipFillPieI(gdip.memory, gdip.brush, x, y + h - d, d, d, 90, 90);
+ }
+}
+
+static void
+nk_gdip_fill_triangle(short x0, short y0, short x1,
+ short y1, short x2, short y2, struct nk_color col)
+{
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ };
+
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ GdipFillPolygonI(gdip.memory, gdip.brush, points, 3, FillModeAlternate);
+}
+
+static void
+nk_gdip_stroke_triangle(short x0, short y0, short x1,
+ short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+ POINT points[] = {
+ { x0, y0 },
+ { x1, y1 },
+ { x2, y2 },
+ { x0, y0 },
+ };
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawPolygonI(gdip.memory, gdip.pen, points, 4);
+}
+
+static void
+nk_gdip_fill_polygon(const struct nk_vec2i *pnts, int count, struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 64
+ POINT points[MAX_POINTS];
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ for (i = 0; i < count && i < MAX_POINTS; ++i) {
+ points[i].x = pnts[i].x;
+ points[i].y = pnts[i].y;
+ }
+ GdipFillPolygonI(gdip.memory, gdip.brush, points, i, FillModeAlternate);
+ #undef MAX_POINTS
+}
+
+static void
+nk_gdip_stroke_polygon(const struct nk_vec2i *pnts, int count,
+ unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (count > 0) {
+ int i;
+ for (i = 1; i < count; ++i)
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
+ }
+}
+
+static void
+nk_gdip_stroke_polyline(const struct nk_vec2i *pnts,
+ int count, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ if (count > 0) {
+ int i;
+ for (i = 1; i < count; ++i)
+ GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+ }
+}
+
+static void
+nk_gdip_fill_circle(short x, short y, unsigned short w,
+ unsigned short h, struct nk_color col)
+{
+ GdipSetSolidFillColor(gdip.brush, convert_color(col));
+ GdipFillEllipseI(gdip.memory, gdip.brush, x, y, w, h);
+}
+
+static void
+nk_gdip_stroke_circle(short x, short y, unsigned short w,
+ unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawEllipseI(gdip.memory, gdip.pen, x, y, w, h);
+}
+
+static void
+nk_gdip_stroke_curve(struct nk_vec2i p1,
+ struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+ unsigned short line_thickness, struct nk_color col)
+{
+ GdipSetPenWidth(gdip.pen, (REAL)line_thickness);
+ GdipSetPenColor(gdip.pen, convert_color(col));
+ GdipDrawBezierI(gdip.memory, gdip.pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);
+}
+
+static void
+nk_gdip_draw_text(short x, short y, unsigned short w, unsigned short h,
+ const char *text, int len, GdipFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+ int wsize;
+ WCHAR* wstr;
+ RectF layout = { (FLOAT)x, (FLOAT)y, (FLOAT)w, (FLOAT)h };
+
+ if(!text || !font || !len) return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ GdipSetSolidFillColor(gdip.brush, convert_color(cbg));
+ GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);
+ GdipSetSolidFillColor(gdip.brush, convert_color(cfg));
+ GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush);
+}
+
+static void
+nk_gdip_clear(struct nk_color col)
+{
+ GdipGraphicsClear(gdip.memory, convert_color(col));
+}
+
+static void
+nk_gdip_blit(GpGraphics *graphics)
+{
+ GdipDrawImageI(graphics, gdip.bitmap, 0, 0);
+}
+
+GdipFont*
+nk_gdipfont_create(const char *name, int size)
+{
+ GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont));
+ GpFontFamily *family;
+
+ int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+ WCHAR* wname = (WCHAR*)_alloca((wsize + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, wsize);
+ wname[wsize] = 0;
+
+ GdipCreateFontFamilyFromName(wname, NULL, &family);
+ GdipCreateFont(family, (REAL)size, FontStyleRegular, UnitPixel, &font->handle);
+ GdipDeleteFontFamily(family);
+
+ return font;
+}
+
+static float
+nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ GdipFont *font = (GdipFont *)handle.ptr;
+ RectF layout = { 0.0f, 0.0f, 65536.0f, 65536.0f };
+ RectF bbox;
+ int wsize;
+ WCHAR* wstr;
+ if (!font || !text)
+ return 0;
+
+ (void)height;
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+ GdipMeasureString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, &bbox, NULL, NULL);
+ return bbox.Width;
+}
+
+void
+nk_gdipfont_del(GdipFont *font)
+{
+ if(!font) return;
+ GdipDeleteFont(font->handle);
+ free(font);
+}
+
+static void
+nk_gdip_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ HGLOBAL mem;
+ SIZE_T size;
+ LPCWSTR wstr;
+ int utf8size;
+ char* utf8;
+ (void)usr;
+
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+ return;
+
+ mem = (HGLOBAL)GetClipboardData(CF_UNICODETEXT);
+ if (!mem) {
+ CloseClipboard();
+ return;
+ }
+
+ size = GlobalSize(mem) - 1;
+ if (!size) {
+ CloseClipboard();
+ return;
+ }
+
+ wstr = (LPCWSTR)GlobalLock(mem);
+ if (!wstr) {
+ CloseClipboard();
+ return;
+ }
+
+ utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);
+ if (!utf8size) {
+ GlobalUnlock(mem);
+ CloseClipboard();
+ return;
+ }
+
+ utf8 = (char*)malloc(utf8size);
+ if (!utf8) {
+ GlobalUnlock(mem);
+ CloseClipboard();
+ return;
+ }
+
+ WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);
+ nk_textedit_paste(edit, utf8, utf8size);
+ free(utf8);
+ GlobalUnlock(mem);
+ CloseClipboard();
+}
+
+static void
+nk_gdip_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ HGLOBAL mem;
+ wchar_t* wstr;
+ int wsize;
+ (void)usr;
+
+ if (!OpenClipboard(NULL))
+ return;
+
+ wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+ if (!wsize) {
+ CloseClipboard();
+ return;
+ }
+
+ mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+ if (!mem) {
+ CloseClipboard();
+ return;
+ }
+
+ wstr = (wchar_t*)GlobalLock(mem);
+ if (!wstr) {
+ GlobalFree(mem);
+ CloseClipboard();
+ return;
+ }
+
+ MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+ wstr[wsize] = 0;
+ GlobalUnlock(mem);
+ if (!SetClipboardData(CF_UNICODETEXT, mem))
+ GlobalFree(mem);
+ CloseClipboard();
+}
+
+NK_API struct nk_context*
+nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height)
+{
+ GdiplusStartupInput startup = { 1, NULL, FALSE, TRUE };
+ GdiplusStartup(&gdip.token, &startup, NULL);
+
+ GdipCreateFromHWND(hwnd, &gdip.window);
+ GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);
+ GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);
+ GdipCreatePen1(0, 1.0f, UnitPixel, &gdip.pen);
+ GdipCreateSolidFill(0, &gdip.brush);
+ GdipStringFormatGetGenericTypographic(&gdip.format);
+ GdipSetStringFormatFlags(gdip.format, StringFormatFlagsNoFitBlackBox |
+ StringFormatFlagsMeasureTrailingSpaces | StringFormatFlagsNoWrap |
+ StringFormatFlagsNoClip);
+
+ nk_init_default(&gdip.ctx, NULL);
+ gdip.ctx.clip.copy = nk_gdip_clipbard_copy;
+ gdip.ctx.clip.paste = nk_gdip_clipbard_paste;
+ return &gdip.ctx;
+}
+
+NK_API void
+nk_gdip_set_font(GdipFont *gdipfont)
+{
+ struct nk_user_font *font = &gdipfont->nk;
+ font->userdata = nk_handle_ptr(gdipfont);
+ GdipGetFontSize(gdipfont->handle, &font->height);
+ font->width = nk_gdipfont_get_text_width;
+ nk_style_set_font(&gdip.ctx, font);
+}
+
+NK_API int
+nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ switch (msg)
+ {
+ case WM_SIZE:
+ if (gdip.window)
+ {
+ unsigned int width = LOWORD(lparam);
+ unsigned int height = HIWORD(lparam);
+ GdipDeleteGraphics(gdip.window);
+ GdipDeleteGraphics(gdip.memory);
+ GdipDisposeImage(gdip.bitmap);
+ GdipCreateFromHWND(wnd, &gdip.window);
+ GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);
+ GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT paint;
+ HDC dc = BeginPaint(wnd, &paint);
+ GpGraphics *graphics;
+ GdipCreateFromHDC(dc, &graphics);
+ nk_gdip_blit(graphics);
+ GdipDeleteGraphics(graphics);
+ EndPaint(wnd, &paint);
+ return 1;
+ }
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ {
+ int down = !((lparam >> 31) & 1);
+ int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+ switch (wparam)
+ {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ nk_input_key(&gdip.ctx, NK_KEY_SHIFT, down);
+ return 1;
+
+ case VK_DELETE:
+ nk_input_key(&gdip.ctx, NK_KEY_DEL, down);
+ return 1;
+
+ case VK_RETURN:
+ nk_input_key(&gdip.ctx, NK_KEY_ENTER, down);
+ return 1;
+
+ case VK_TAB:
+ nk_input_key(&gdip.ctx, NK_KEY_TAB, down);
+ return 1;
+
+ case VK_LEFT:
+ if (ctrl)
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else
+ nk_input_key(&gdip.ctx, NK_KEY_LEFT, down);
+ return 1;
+
+ case VK_RIGHT:
+ if (ctrl)
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else
+ nk_input_key(&gdip.ctx, NK_KEY_RIGHT, down);
+ return 1;
+
+ case VK_BACK:
+ nk_input_key(&gdip.ctx, NK_KEY_BACKSPACE, down);
+ return 1;
+
+ case VK_HOME:
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_START, down);
+ return 1;
+
+ case VK_END:
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_END, down);
+ return 1;
+
+ case VK_NEXT:
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_DOWN, down);
+ return 1;
+
+ case VK_PRIOR:
+ nk_input_key(&gdip.ctx, NK_KEY_SCROLL_UP, down);
+ return 1;
+
+ case 'C':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_COPY, down);
+ return 1;
+ }
+ break;
+
+ case 'V':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_PASTE, down);
+ return 1;
+ }
+ break;
+
+ case 'X':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_CUT, down);
+ return 1;
+ }
+ break;
+
+ case 'Z':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_UNDO, down);
+ return 1;
+ }
+ break;
+
+ case 'R':
+ if (ctrl) {
+ nk_input_key(&gdip.ctx, NK_KEY_TEXT_REDO, down);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+ }
+
+ case WM_CHAR:
+ if (wparam >= 32)
+ {
+ nk_input_unicode(&gdip.ctx, (nk_rune)wparam);
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_LBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_RBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_RBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MBUTTONDOWN:
+ nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+ SetCapture(wnd);
+ return 1;
+
+ case WM_MBUTTONUP:
+ nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+ ReleaseCapture();
+ return 1;
+
+ case WM_MOUSEWHEEL:
+ nk_input_scroll(&gdip.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+ return 1;
+
+ case WM_MOUSEMOVE:
+ nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+ return 1;
+ }
+
+ return 0;
+}
+
+NK_API void
+nk_gdip_shutdown(void)
+{
+ GdipDeleteGraphics(gdip.window);
+ GdipDeleteGraphics(gdip.memory);
+ GdipDisposeImage(gdip.bitmap);
+ GdipDeletePen(gdip.pen);
+ GdipDeleteBrush(gdip.brush);
+ GdipDeleteStringFormat(gdip.format);
+ GdiplusShutdown(gdip.token);
+
+ nk_free(&gdip.ctx);
+}
+
+NK_API void
+nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear)
+{
+ const struct nk_command *cmd;
+
+ GdipSetTextRenderingHint(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?
+ TextRenderingHintClearTypeGridFit : TextRenderingHintSingleBitPerPixelGridFit);
+ GdipSetSmoothingMode(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?
+ SmoothingModeHighQuality : SmoothingModeNone);
+ nk_gdip_clear(clear);
+
+ nk_foreach(cmd, &gdip.ctx)
+ {
+ switch (cmd->type) {
+ case NK_COMMAND_NOP: break;
+ case NK_COMMAND_SCISSOR: {
+ const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+ nk_gdip_scissor(s->x, s->y, s->w, s->h);
+ } break;
+ case NK_COMMAND_LINE: {
+ const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+ nk_gdip_stroke_line(l->begin.x, l->begin.y, l->end.x,
+ l->end.y, l->line_thickness, l->color);
+ } break;
+ case NK_COMMAND_RECT: {
+ const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+ nk_gdip_stroke_rect(r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->line_thickness, r->color);
+ } break;
+ case NK_COMMAND_RECT_FILLED: {
+ const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+ nk_gdip_fill_rect(r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->color);
+ } break;
+ case NK_COMMAND_CIRCLE: {
+ const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+ nk_gdip_stroke_circle(c->x, c->y, c->w, c->h, c->line_thickness, c->color);
+ } break;
+ case NK_COMMAND_CIRCLE_FILLED: {
+ const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+ nk_gdip_fill_circle(c->x, c->y, c->w, c->h, c->color);
+ } break;
+ case NK_COMMAND_TRIANGLE: {
+ const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+ nk_gdip_stroke_triangle(t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->line_thickness, t->color);
+ } break;
+ case NK_COMMAND_TRIANGLE_FILLED: {
+ const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+ nk_gdip_fill_triangle(t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->color);
+ } break;
+ case NK_COMMAND_POLYGON: {
+ const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
+ nk_gdip_stroke_polygon(p->points, p->point_count, p->line_thickness,p->color);
+ } break;
+ case NK_COMMAND_POLYGON_FILLED: {
+ const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+ nk_gdip_fill_polygon(p->points, p->point_count, p->color);
+ } break;
+ case NK_COMMAND_POLYLINE: {
+ const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+ nk_gdip_stroke_polyline(p->points, p->point_count, p->line_thickness, p->color);
+ } break;
+ case NK_COMMAND_TEXT: {
+ const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+ nk_gdip_draw_text(t->x, t->y, t->w, t->h,
+ (const char*)t->string, t->length,
+ (GdipFont*)t->font->userdata.ptr,
+ t->background, t->foreground);
+ } break;
+ case NK_COMMAND_CURVE: {
+ const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+ nk_gdip_stroke_curve(q->begin, q->ctrl[0], q->ctrl[1],
+ q->end, q->line_thickness, q->color);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_IMAGE:
+ case NK_COMMAND_ARC:
+ case NK_COMMAND_ARC_FILLED:
+ default: break;
+ }
+ }
+ nk_gdip_blit(gdip.window);
+ nk_clear(&gdip.ctx);
+}
+
+#endif
+
diff --git a/nuklear/demo/glfw_opengl2/Makefile b/nuklear/demo/glfw_opengl2/Makefile
new file mode 100644
index 0000000..c937eb8
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lglfw3 -lopengl32 -lm -lGLU32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lglfw3 -framework OpenGL -lm
+ else
+ LIBS = -lglfw -lGL -lm -lGLU
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/glfw_opengl2/main.c b/nuklear/demo/glfw_opengl2/main.c
new file mode 100644
index 0000000..1c0f284
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/main.c
@@ -0,0 +1,165 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_GLFW_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_glfw_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static void error_callback(int e, const char *d)
+{printf("Error %d: %s\n", e, d);}
+
+int main(void)
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* GUI */
+ ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_glfw3_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_glfw3_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* Input */
+ glfwPollEvents();
+ nk_glfw3_new_frame();
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ glfwGetWindowSize(win, &width, &height);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state
+ * with blending, scissor, face culling and depth test and defaults everything
+ * back into a default state. Make sure to either save and restore or
+ * reset your own state after drawing rendering the UI. */
+ nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glfwSwapBuffers(win);}
+ }
+ nk_glfw3_shutdown();
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h b/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h
new file mode 100644
index 0000000..93af773
--- /dev/null
+++ b/nuklear/demo/glfw_opengl2/nuklear_glfw_gl2.h
@@ -0,0 +1,350 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GLFW_GL2_H_
+#define NK_GLFW_GL2_H_
+
+#include <GLFW/glfw3.h>
+
+enum nk_glfw_init_state{
+ NK_GLFW3_DEFAULT = 0,
+ NK_GLFW3_INSTALL_CALLBACKS
+};
+NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);
+NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_glfw3_font_stash_end(void);
+
+NK_API void nk_glfw3_new_frame(void);
+NK_API void nk_glfw3_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_glfw3_shutdown(void);
+
+NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
+NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GLFW_GL2_IMPLEMENTATION
+
+#ifndef NK_GLFW_TEXT_MAX
+#define NK_GLFW_TEXT_MAX 256
+#endif
+
+struct nk_glfw_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_glfw {
+ GLFWwindow *win;
+ int width, height;
+ int display_width, display_height;
+ struct nk_glfw_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_vec2 fb_scale;
+ unsigned int text[NK_GLFW_TEXT_MAX];
+ int text_len;
+ float scroll;
+} glfw;
+
+NK_INTERN void
+nk_glfw3_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_glfw_device *dev = &glfw.ogl;
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * glfw.fb_scale.x),
+ (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),
+ (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),
+ (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&glfw.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+NK_API void
+nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
+{
+ (void)win;
+ if (glfw.text_len < NK_GLFW_TEXT_MAX)
+ glfw.text[glfw.text_len++] = codepoint;
+}
+
+NK_API void
+nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
+{
+ (void)win; (void)xoff;
+ glfw.scroll += (float)yoff;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ const char *text = glfwGetClipboardString(glfw.win);
+ if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ glfwSetClipboardString(glfw.win, str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
+{
+ glfw.win = win;
+ if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
+ glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
+ glfwSetCharCallback(win, nk_glfw3_char_callback);
+ }
+
+ nk_init_default(&glfw.ctx, 0);
+ glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
+ glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
+ glfw.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_buffer_init_default(&glfw.ogl.cmds);
+ return &glfw.ctx;
+}
+
+NK_API void
+nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&glfw.atlas);
+ nk_font_atlas_begin(&glfw.atlas);
+ *atlas = &glfw.atlas;
+}
+
+NK_API void
+nk_glfw3_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_glfw3_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null);
+ if (glfw.atlas.default_font)
+ nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);
+}
+
+NK_API void
+nk_glfw3_new_frame(void)
+{
+ int i;
+ double x, y;
+ struct nk_context *ctx = &glfw.ctx;
+ struct GLFWwindow *win = glfw.win;
+
+ glfwGetWindowSize(win, &glfw.width, &glfw.height);
+ glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);
+ glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;
+ glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;
+
+ nk_input_begin(ctx);
+ for (i = 0; i < glfw.text_len; ++i)
+ nk_input_unicode(ctx, glfw.text[i]);
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ else if (ctx->input.mouse.ungrab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
+ nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
+ glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
+
+ if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+ glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
+ nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+ } else {
+ nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_COPY, 0);
+ nk_input_key(ctx, NK_KEY_PASTE, 0);
+ nk_input_key(ctx, NK_KEY_CUT, 0);
+ nk_input_key(ctx, NK_KEY_SHIFT, 0);
+ }
+
+ glfwGetCursorPos(win, &x, &y);
+ nk_input_motion(ctx, (int)x, (int)y);
+ if (ctx->input.mouse.grabbed) {
+ glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ }
+
+ nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_scroll(ctx, glfw.scroll);
+ nk_input_end(&glfw.ctx);
+ glfw.text_len = 0;
+ glfw.scroll = 0;
+}
+
+NK_API
+void nk_glfw3_shutdown(void)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ nk_font_atlas_clear(&glfw.atlas);
+ nk_free(&glfw.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ memset(&glfw, 0, sizeof(glfw));
+}
+
+#endif
diff --git a/nuklear/demo/glfw_opengl3/Makefile b/nuklear/demo/glfw_opengl3/Makefile
new file mode 100644
index 0000000..7f620ea
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lglfw3 -framework OpenGL -lm -lGLEW
+ else
+ LIBS = -lglfw -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/glfw_opengl3/main.c b/nuklear/demo/glfw_opengl3/main.c
new file mode 100644
index 0000000..d74ee56
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/main.c
@@ -0,0 +1,180 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_GLFW_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_glfw_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+static void error_callback(int e, const char *d)
+{printf("Error %d: %s\n", e, d);}
+
+int main(void)
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* OpenGL */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_glfw3_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_glfw3_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* Input */
+ glfwPollEvents();
+ nk_glfw3_new_frame();
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ glfwGetWindowSize(win, &width, &height);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glfwSwapBuffers(win);}
+ }
+ nk_glfw3_shutdown();
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h b/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h
new file mode 100644
index 0000000..aabb365
--- /dev/null
+++ b/nuklear/demo/glfw_opengl3/nuklear_glfw_gl3.h
@@ -0,0 +1,456 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_GLFW_GL3_H_
+#define NK_GLFW_GL3_H_
+
+#include <GLFW/glfw3.h>
+
+enum nk_glfw_init_state{
+ NK_GLFW3_DEFAULT=0,
+ NK_GLFW3_INSTALL_CALLBACKS
+};
+
+NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);
+NK_API void nk_glfw3_shutdown(void);
+NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_glfw3_font_stash_end(void);
+NK_API void nk_glfw3_new_frame(void);
+NK_API void nk_glfw3_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+
+NK_API void nk_glfw3_device_destroy(void);
+NK_API void nk_glfw3_device_create(void);
+
+NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
+NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GLFW_GL3_IMPLEMENTATION
+
+#ifndef NK_GLFW_TEXT_MAX
+#define NK_GLFW_TEXT_MAX 256
+#endif
+
+struct nk_glfw_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_glfw {
+ GLFWwindow *win;
+ int width, height;
+ int display_width, display_height;
+ struct nk_glfw_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ struct nk_vec2 fb_scale;
+ unsigned int text[NK_GLFW_TEXT_MAX];
+ int text_len;
+ float scroll;
+} glfw;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+NK_API void
+nk_glfw3_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ struct nk_glfw_device *dev = &glfw.ogl;
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+NK_INTERN void
+nk_glfw3_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_glfw3_device_destroy(void)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ struct nk_glfw_device *dev = &glfw.ogl;
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)glfw.width;
+ ortho[1][1] /= (GLfloat)glfw.height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
+ nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
+ nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * glfw.fb_scale.x),
+ (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),
+ (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),
+ (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&glfw.ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+NK_API void
+nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
+{
+ (void)win;
+ if (glfw.text_len < NK_GLFW_TEXT_MAX)
+ glfw.text[glfw.text_len++] = codepoint;
+}
+
+NK_API void
+nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
+{
+ (void)win; (void)xoff;
+ glfw.scroll += (float)yoff;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ const char *text = glfwGetClipboardString(glfw.win);
+ if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+}
+
+NK_INTERN void
+nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ glfwSetClipboardString(glfw.win, str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
+{
+ glfw.win = win;
+ if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
+ glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
+ glfwSetCharCallback(win, nk_glfw3_char_callback);
+ }
+
+ nk_init_default(&glfw.ctx, 0);
+ glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
+ glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
+ glfw.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_glfw3_device_create();
+ return &glfw.ctx;
+}
+
+NK_API void
+nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&glfw.atlas);
+ nk_font_atlas_begin(&glfw.atlas);
+ *atlas = &glfw.atlas;
+}
+
+NK_API void
+nk_glfw3_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_glfw3_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null);
+ if (glfw.atlas.default_font)
+ nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);
+}
+
+NK_API void
+nk_glfw3_new_frame(void)
+{
+ int i;
+ double x, y;
+ struct nk_context *ctx = &glfw.ctx;
+ struct GLFWwindow *win = glfw.win;
+
+ glfwGetWindowSize(win, &glfw.width, &glfw.height);
+ glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);
+ glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;
+ glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;
+
+ nk_input_begin(ctx);
+ for (i = 0; i < glfw.text_len; ++i)
+ nk_input_unicode(ctx, glfw.text[i]);
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ else if (ctx->input.mouse.ungrab)
+ glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
+ nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
+ glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
+
+ if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+ glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
+ nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+ } else {
+ nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_COPY, 0);
+ nk_input_key(ctx, NK_KEY_PASTE, 0);
+ nk_input_key(ctx, NK_KEY_CUT, 0);
+ nk_input_key(ctx, NK_KEY_SHIFT, 0);
+ }
+
+ glfwGetCursorPos(win, &x, &y);
+ nk_input_motion(ctx, (int)x, (int)y);
+ if (ctx->input.mouse.grabbed) {
+ glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ }
+
+ nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_scroll(ctx, glfw.scroll);
+ nk_input_end(&glfw.ctx);
+ glfw.text_len = 0;
+ glfw.scroll = 0;
+}
+
+NK_API
+void nk_glfw3_shutdown(void)
+{
+ nk_font_atlas_clear(&glfw.atlas);
+ nk_free(&glfw.ctx);
+ nk_glfw3_device_destroy();
+ memset(&glfw, 0, sizeof(glfw));
+}
+
+#endif
diff --git a/nuklear/demo/node_editor.c b/nuklear/demo/node_editor.c
new file mode 100644
index 0000000..6949f59
--- /dev/null
+++ b/nuklear/demo/node_editor.c
@@ -0,0 +1,343 @@
+/* nuklear - v1.00 - public domain */
+/* This is a simple node editor just to show a simple implementation and that
+ * it is possible to achieve it with this library. While all nodes inside this
+ * example use a simple color modifier as content you could change them
+ * to have your custom content depending on the node time.
+ * Biggest difference to most usual implementation is that this example does
+ * not have connectors on the right position of the property that it links.
+ * This is mainly done out of laziness and could be implemented as well but
+ * requires calculating the position of all rows and add connectors.
+ * In addition adding and removing nodes is quite limited at the
+ * moment since it is based on a simple fixed array. If this is to be converted
+ * into something more serious it is probably best to extend it.*/
+struct node {
+ int ID;
+ char name[32];
+ struct nk_rect bounds;
+ float value;
+ struct nk_color color;
+ int input_count;
+ int output_count;
+ struct node *next;
+ struct node *prev;
+};
+
+struct node_link {
+ int input_id;
+ int input_slot;
+ int output_id;
+ int output_slot;
+ struct nk_vec2 in;
+ struct nk_vec2 out;
+};
+
+struct node_linking {
+ int active;
+ struct node *node;
+ int input_id;
+ int input_slot;
+};
+
+struct node_editor {
+ int initialized;
+ struct node node_buf[32];
+ struct node_link links[64];
+ struct node *begin;
+ struct node *end;
+ int node_count;
+ int link_count;
+ struct nk_rect bounds;
+ struct node *selected;
+ int show_grid;
+ struct nk_vec2 scrolling;
+ struct node_linking linking;
+};
+static struct node_editor nodeEditor;
+
+static void
+node_editor_push(struct node_editor *editor, struct node *node)
+{
+ if (!editor->begin) {
+ node->next = NULL;
+ node->prev = NULL;
+ editor->begin = node;
+ editor->end = node;
+ } else {
+ node->prev = editor->end;
+ if (editor->end)
+ editor->end->next = node;
+ node->next = NULL;
+ editor->end = node;
+ }
+}
+
+static void
+node_editor_pop(struct node_editor *editor, struct node *node)
+{
+ if (node->next)
+ node->next->prev = node->prev;
+ if (node->prev)
+ node->prev->next = node->next;
+ if (editor->end == node)
+ editor->end = node->prev;
+ if (editor->begin == node)
+ editor->begin = node->next;
+ node->next = NULL;
+ node->prev = NULL;
+}
+
+static struct node*
+node_editor_find(struct node_editor *editor, int ID)
+{
+ struct node *iter = editor->begin;
+ while (iter) {
+ if (iter->ID == ID)
+ return iter;
+ iter = iter->next;
+ }
+ return NULL;
+}
+
+static void
+node_editor_add(struct node_editor *editor, const char *name, struct nk_rect bounds,
+ struct nk_color col, int in_count, int out_count)
+{
+ static int IDs = 0;
+ struct node *node;
+ assert((nk_size)editor->node_count < LEN(editor->node_buf));
+ node = &editor->node_buf[editor->node_count++];
+ node->ID = IDs++;
+ node->value = 0;
+ node->color = nk_rgb(255, 0, 0);
+ node->input_count = in_count;
+ node->output_count = out_count;
+ node->color = col;
+ node->bounds = bounds;
+ strcpy(node->name, name);
+ node_editor_push(editor, node);
+}
+
+static void
+node_editor_link(struct node_editor *editor, int in_id, int in_slot,
+ int out_id, int out_slot)
+{
+ struct node_link *link;
+ assert((nk_size)editor->link_count < LEN(editor->links));
+ link = &editor->links[editor->link_count++];
+ link->input_id = in_id;
+ link->input_slot = in_slot;
+ link->output_id = out_id;
+ link->output_slot = out_slot;
+}
+
+static void
+node_editor_init(struct node_editor *editor)
+{
+ memset(editor, 0, sizeof(*editor));
+ editor->begin = NULL;
+ editor->end = NULL;
+ node_editor_add(editor, "Source", nk_rect(40, 10, 180, 220), nk_rgb(255, 0, 0), 0, 1);
+ node_editor_add(editor, "Source", nk_rect(40, 260, 180, 220), nk_rgb(0, 255, 0), 0, 1);
+ node_editor_add(editor, "Combine", nk_rect(400, 100, 180, 220), nk_rgb(0,0,255), 2, 2);
+ node_editor_link(editor, 0, 0, 2, 0);
+ node_editor_link(editor, 1, 0, 2, 1);
+ editor->show_grid = nk_true;
+}
+
+static int
+node_editor(struct nk_context *ctx)
+{
+ int n = 0;
+ struct nk_rect total_space;
+ const struct nk_input *in = &ctx->input;
+ struct nk_command_buffer *canvas;
+ struct node *updated = 0;
+ struct node_editor *nodedit = &nodeEditor;
+
+ if (!nodeEditor.initialized) {
+ node_editor_init(&nodeEditor);
+ nodeEditor.initialized = 1;
+ }
+
+ if (nk_begin(ctx, "NodeEdit", nk_rect(0, 0, 800, 600),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE))
+ {
+ /* allocate complete window space */
+ canvas = nk_window_get_canvas(ctx);
+ total_space = nk_window_get_content_region(ctx);
+ nk_layout_space_begin(ctx, NK_STATIC, total_space.h, nodedit->node_count);
+ {
+ struct node *it = nodedit->begin;
+ struct nk_rect size = nk_layout_space_bounds(ctx);
+
+ if (nodedit->show_grid) {
+ /* display grid */
+ float x, y;
+ const float grid_size = 32.0f;
+ const struct nk_color grid_color = nk_rgb(50, 50, 50);
+ for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size)
+ nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color);
+ for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size)
+ nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color);
+ }
+
+ /* execute each node as a movable group */
+ struct nk_panel *node;
+ while (it) {
+ /* calculate scrolled node window position and size */
+ nk_layout_space_push(ctx, nk_rect(it->bounds.x - nodedit->scrolling.x,
+ it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h));
+
+ /* execute node window */
+ if (nk_group_begin(ctx, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE))
+ {
+ /* always have last selected node on top */
+
+ node = nk_window_get_panel(ctx);
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, node->bounds) &&
+ (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
+ nk_layout_space_rect_to_screen(ctx, node->bounds)))) &&
+ nodedit->end != it)
+ {
+ updated = it;
+ }
+
+ /* ================= NODE CONTENT =====================*/
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_color(ctx, it->color);
+ it->color.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1);
+ it->color.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1);
+ it->color.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1);
+ it->color.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1);
+ /* ====================================================*/
+ nk_group_end(ctx);
+ }
+ {
+ /* node connector and linking */
+ float space;
+ struct nk_rect bounds;
+ bounds = nk_layout_space_rect_to_local(ctx, node->bounds);
+ bounds.x += nodedit->scrolling.x;
+ bounds.y += nodedit->scrolling.y;
+ it->bounds = bounds;
+
+ /* output connector */
+ space = node->bounds.h / (float)((it->output_count) + 1);
+ for (n = 0; n < it->output_count; ++n) {
+ struct nk_rect circle;
+ circle.x = node->bounds.x + node->bounds.w-4;
+ circle.y = node->bounds.y + space * (float)(n+1);
+ circle.w = 8; circle.h = 8;
+ nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
+
+ /* start linking process */
+ if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
+ nodedit->linking.active = nk_true;
+ nodedit->linking.node = it;
+ nodedit->linking.input_id = it->ID;
+ nodedit->linking.input_slot = n;
+ }
+
+ /* draw curve from linked node slot to mouse position */
+ if (nodedit->linking.active && nodedit->linking.node == it &&
+ nodedit->linking.input_slot == n) {
+ struct nk_vec2 l0 = nk_vec2(circle.x + 3, circle.y + 3);
+ struct nk_vec2 l1 = in->mouse.pos;
+ nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
+ l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
+ }
+ }
+
+ /* input connector */
+ space = node->bounds.h / (float)((it->input_count) + 1);
+ for (n = 0; n < it->input_count; ++n) {
+ struct nk_rect circle;
+ circle.x = node->bounds.x-4;
+ circle.y = node->bounds.y + space * (float)(n+1);
+ circle.w = 8; circle.h = 8;
+ nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
+ if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
+ nk_input_is_mouse_hovering_rect(in, circle) &&
+ nodedit->linking.active && nodedit->linking.node != it) {
+ nodedit->linking.active = nk_false;
+ node_editor_link(nodedit, nodedit->linking.input_id,
+ nodedit->linking.input_slot, it->ID, n);
+ }
+ }
+ }
+ it = it->next;
+ }
+
+ /* reset linking connection */
+ if (nodedit->linking.active && nk_input_is_mouse_released(in, NK_BUTTON_LEFT)) {
+ nodedit->linking.active = nk_false;
+ nodedit->linking.node = NULL;
+ fprintf(stdout, "linking failed\n");
+ }
+
+ /* draw each link */
+ for (n = 0; n < nodedit->link_count; ++n) {
+ struct node_link *link = &nodedit->links[n];
+ struct node *ni = node_editor_find(nodedit, link->input_id);
+ struct node *no = node_editor_find(nodedit, link->output_id);
+ float spacei = node->bounds.h / (float)((ni->output_count) + 1);
+ float spaceo = node->bounds.h / (float)((no->input_count) + 1);
+ struct nk_vec2 l0 = nk_layout_space_to_screen(ctx,
+ nk_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1)));
+ struct nk_vec2 l1 = nk_layout_space_to_screen(ctx,
+ nk_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1)));
+
+ l0.x -= nodedit->scrolling.x;
+ l0.y -= nodedit->scrolling.y;
+ l1.x -= nodedit->scrolling.x;
+ l1.y -= nodedit->scrolling.y;
+ nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
+ l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
+ }
+
+ if (updated) {
+ /* reshuffle nodes to have least recently selected node on top */
+ node_editor_pop(nodedit, updated);
+ node_editor_push(nodedit, updated);
+ }
+
+ /* node selection */
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ctx))) {
+ it = nodedit->begin;
+ nodedit->selected = NULL;
+ nodedit->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
+ while (it) {
+ struct nk_rect b = nk_layout_space_rect_to_screen(ctx, it->bounds);
+ b.x -= nodedit->scrolling.x;
+ b.y -= nodedit->scrolling.y;
+ if (nk_input_is_mouse_hovering_rect(in, b))
+ nodedit->selected = it;
+ it = it->next;
+ }
+ }
+
+ /* contextual menu */
+ if (nk_contextual_begin(ctx, 0, nk_vec2(100, 220), nk_window_get_bounds(ctx))) {
+ const char *grid_option[] = {"Show Grid", "Hide Grid"};
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_contextual_item_label(ctx, "New", NK_TEXT_CENTERED))
+ node_editor_add(nodedit, "New", nk_rect(400, 260, 180, 220),
+ nk_rgb(255, 255, 255), 1, 2);
+ if (nk_contextual_item_label(ctx, grid_option[nodedit->show_grid],NK_TEXT_CENTERED))
+ nodedit->show_grid = !nodedit->show_grid;
+ nk_contextual_end(ctx);
+ }
+ }
+ nk_layout_space_end(ctx);
+
+ /* window content scrolling */
+ if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ctx)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
+ nodedit->scrolling.x += in->mouse.delta.x;
+ nodedit->scrolling.y += in->mouse.delta.y;
+ }
+ }
+ nk_end(ctx);
+ return !nk_window_is_closed(ctx, "NodeEdit");
+}
+
diff --git a/nuklear/demo/overview.c b/nuklear/demo/overview.c
new file mode 100644
index 0000000..e271318
--- /dev/null
+++ b/nuklear/demo/overview.c
@@ -0,0 +1,1188 @@
+
+static int
+overview(struct nk_context *ctx)
+{
+ /* window flags */
+ static int show_menu = nk_true;
+ static int titlebar = nk_true;
+ static int border = nk_true;
+ static int resize = nk_true;
+ static int movable = nk_true;
+ static int no_scrollbar = nk_false;
+ static nk_flags window_flags = 0;
+ static int minimizable = nk_true;
+
+ /* popups */
+ static enum nk_style_header_align header_align = NK_HEADER_RIGHT;
+ static int show_app_about = nk_false;
+
+ /* window flags */
+ window_flags = 0;
+ ctx->style.window.header.align = header_align;
+ if (border) window_flags |= NK_WINDOW_BORDER;
+ if (resize) window_flags |= NK_WINDOW_SCALABLE;
+ if (movable) window_flags |= NK_WINDOW_MOVABLE;
+ if (no_scrollbar) window_flags |= NK_WINDOW_NO_SCROLLBAR;
+ if (minimizable) window_flags |= NK_WINDOW_MINIMIZABLE;
+
+ if (nk_begin(ctx, "Overview", nk_rect(10, 10, 400, 600), window_flags))
+ {
+ if (show_menu)
+ {
+ /* menubar */
+ enum menu_states {MENU_DEFAULT, MENU_WINDOWS};
+ static nk_size mprog = 60;
+ static int mslider = 10;
+ static int mcheck = nk_true;
+
+ nk_menubar_begin(ctx);
+ nk_layout_row_begin(ctx, NK_STATIC, 25, 4);
+ nk_layout_row_push(ctx, 45);
+ if (nk_menu_begin_label(ctx, "MENU", NK_TEXT_LEFT, nk_vec2(120, 200)))
+ {
+ static size_t prog = 40;
+ static int slider = 10;
+ static int check = nk_true;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_menu_item_label(ctx, "Hide", NK_TEXT_LEFT))
+ show_menu = nk_false;
+ if (nk_menu_item_label(ctx, "About", NK_TEXT_LEFT))
+ show_app_about = nk_true;
+ nk_progress(ctx, &prog, 100, NK_MODIFIABLE);
+ nk_slider_int(ctx, 0, &slider, 16, 1);
+ nk_checkbox_label(ctx, "check", &check);
+ nk_menu_end(ctx);
+ }
+ nk_layout_row_push(ctx, 70);
+ nk_progress(ctx, &mprog, 100, NK_MODIFIABLE);
+ nk_slider_int(ctx, 0, &mslider, 16, 1);
+ nk_checkbox_label(ctx, "check", &mcheck);
+ nk_menubar_end(ctx);
+ }
+
+ if (show_app_about)
+ {
+ /* about popup */
+ static struct nk_rect s = {20, 100, 300, 190};
+ if (nk_popup_begin(ctx, NK_POPUP_STATIC, "About", NK_WINDOW_CLOSABLE, s))
+ {
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "Nuklear", NK_TEXT_LEFT);
+ nk_label(ctx, "By Micha Mettke", NK_TEXT_LEFT);
+ nk_label(ctx, "nuklear is licensed under the public domain License.", NK_TEXT_LEFT);
+ nk_popup_end(ctx);
+ } else show_app_about = nk_false;
+ }
+
+ /* window flags */
+ if (nk_tree_push(ctx, NK_TREE_TAB, "Window", NK_MINIMIZED)) {
+ nk_layout_row_dynamic(ctx, 30, 2);
+ nk_checkbox_label(ctx, "Titlebar", &titlebar);
+ nk_checkbox_label(ctx, "Menu", &show_menu);
+ nk_checkbox_label(ctx, "Border", &border);
+ nk_checkbox_label(ctx, "Resizable", &resize);
+ nk_checkbox_label(ctx, "Movable", &movable);
+ nk_checkbox_label(ctx, "No Scrollbar", &no_scrollbar);
+ nk_checkbox_label(ctx, "Minimizable", &minimizable);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_TAB, "Widgets", NK_MINIMIZED))
+ {
+ enum options {A,B,C};
+ static int checkbox;
+ static int option;
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Text", NK_MINIMIZED))
+ {
+ /* Text Widgets */
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "Label aligned left", NK_TEXT_LEFT);
+ nk_label(ctx, "Label aligned centered", NK_TEXT_CENTERED);
+ nk_label(ctx, "Label aligned right", NK_TEXT_RIGHT);
+ nk_label_colored(ctx, "Blue text", NK_TEXT_LEFT, nk_rgb(0,0,255));
+ nk_label_colored(ctx, "Yellow text", NK_TEXT_LEFT, nk_rgb(255,255,0));
+ nk_text(ctx, "Text without /0", 15, NK_TEXT_RIGHT);
+
+ nk_layout_row_static(ctx, 100, 200, 1);
+ nk_label_wrap(ctx, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping");
+ nk_layout_row_dynamic(ctx, 100, 1);
+ nk_label_wrap(ctx, "This is another long text to show dynamic window changes on multiline text");
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Button", NK_MINIMIZED))
+ {
+ /* Buttons Widgets */
+ nk_layout_row_static(ctx, 30, 100, 3);
+ if (nk_button_label(ctx, "Button"))
+ fprintf(stdout, "Button pressed!\n");
+ nk_button_set_behavior(ctx, NK_BUTTON_REPEATER);
+ if (nk_button_label(ctx, "Repeater"))
+ fprintf(stdout, "Repeater is being pressed!\n");
+ nk_button_set_behavior(ctx, NK_BUTTON_DEFAULT);
+ nk_button_color(ctx, nk_rgb(0,0,255));
+
+ nk_layout_row_static(ctx, 25, 25, 8);
+ nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_SOLID);
+ nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_OUTLINE);
+ nk_button_symbol(ctx, NK_SYMBOL_RECT_SOLID);
+ nk_button_symbol(ctx, NK_SYMBOL_RECT_OUTLINE);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT);
+ nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT);
+
+ nk_layout_row_static(ctx, 30, 100, 2);
+ nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_LEFT, "prev", NK_TEXT_RIGHT);
+ nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_RIGHT, "next", NK_TEXT_LEFT);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Basic", NK_MINIMIZED))
+ {
+ /* Basic widgets */
+ static int int_slider = 5;
+ static float float_slider = 2.5f;
+ static size_t prog_value = 40;
+ static float property_float = 2;
+ static int property_int = 10;
+ static int property_neg = 10;
+
+ static float range_float_min = 0;
+ static float range_float_max = 100;
+ static float range_float_value = 50;
+ static int range_int_min = 0;
+ static int range_int_value = 2048;
+ static int range_int_max = 4096;
+ static const float ratio[] = {120, 150};
+
+ nk_layout_row_static(ctx, 30, 100, 1);
+ nk_checkbox_label(ctx, "Checkbox", &checkbox);
+
+ nk_layout_row_static(ctx, 30, 80, 3);
+ option = nk_option_label(ctx, "optionA", option == A) ? A : option;
+ option = nk_option_label(ctx, "optionB", option == B) ? B : option;
+ option = nk_option_label(ctx, "optionC", option == C) ? C : option;
+
+
+ nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);
+ nk_labelf(ctx, NK_TEXT_LEFT, "Slider int");
+ nk_slider_int(ctx, 0, &int_slider, 10, 1);
+
+ nk_label(ctx, "Slider float", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 0, &float_slider, 5.0, 0.5f);
+ nk_labelf(ctx, NK_TEXT_LEFT, "Progressbar" , prog_value);
+ nk_progress(ctx, &prog_value, 100, NK_MODIFIABLE);
+
+ nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+ nk_label(ctx, "Property float:", NK_TEXT_LEFT);
+ nk_property_float(ctx, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f);
+ nk_label(ctx, "Property int:", NK_TEXT_LEFT);
+ nk_property_int(ctx, "Int:", 0, &property_int, 100.0f, 1, 1);
+ nk_label(ctx, "Property neg:", NK_TEXT_LEFT);
+ nk_property_int(ctx, "Neg:", -10, &property_neg, 10, 1, 1);
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_label(ctx, "Range:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_property_float(ctx, "#min:", 0, &range_float_min, range_float_max, 1.0f, 0.2f);
+ nk_property_float(ctx, "#float:", range_float_min, &range_float_value, range_float_max, 1.0f, 0.2f);
+ nk_property_float(ctx, "#max:", range_float_min, &range_float_max, 100, 1.0f, 0.2f);
+
+ nk_property_int(ctx, "#min:", INT_MIN, &range_int_min, range_int_max, 1, 10);
+ nk_property_int(ctx, "#neg:", range_int_min, &range_int_value, range_int_max, 1, 10);
+ nk_property_int(ctx, "#max:", range_int_min, &range_int_max, INT_MAX, 1, 10);
+
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Selectable", NK_MINIMIZED))
+ {
+ if (nk_tree_push(ctx, NK_TREE_NODE, "List", NK_MINIMIZED))
+ {
+ static int selected[4] = {nk_false, nk_false, nk_true, nk_false};
+ nk_layout_row_static(ctx, 18, 100, 1);
+ nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[0]);
+ nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[1]);
+ nk_label(ctx, "Not Selectable", NK_TEXT_LEFT);
+ nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[2]);
+ nk_selectable_label(ctx, "Selectable", NK_TEXT_LEFT, &selected[3]);
+ nk_tree_pop(ctx);
+ }
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Grid", NK_MINIMIZED))
+ {
+ int i;
+ static int selected[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
+ nk_layout_row_static(ctx, 50, 50, 4);
+ for (i = 0; i < 16; ++i) {
+ if (nk_selectable_label(ctx, "Z", NK_TEXT_CENTERED, &selected[i])) {
+ int x = (i % 4), y = i / 4;
+ if (x > 0) selected[i - 1] ^= 1;
+ if (x < 3) selected[i + 1] ^= 1;
+ if (y > 0) selected[i - 4] ^= 1;
+ if (y < 3) selected[i + 4] ^= 1;
+ }
+ }
+ nk_tree_pop(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Combo", NK_MINIMIZED))
+ {
+ /* Combobox Widgets
+ * In this library comboboxes are not limited to being a popup
+ * list of selectable text. Instead it is a abstract concept of
+ * having something that is *selected* or displayed, a popup window
+ * which opens if something needs to be modified and the content
+ * of the popup which causes the *selected* or displayed value to
+ * change or if wanted close the combobox.
+ *
+ * While strange at first handling comboboxes in a abstract way
+ * solves the problem of overloaded window content. For example
+ * changing a color value requires 4 value modifier (slider, property,...)
+ * for RGBA then you need a label and ways to display the current color.
+ * If you want to go fancy you even add rgb and hsv ratio boxes.
+ * While fine for one color if you have a lot of them it because
+ * tedious to look at and quite wasteful in space. You could add
+ * a popup which modifies the color but this does not solve the
+ * fact that it still requires a lot of cluttered space to do.
+ *
+ * In these kind of instance abstract comboboxes are quite handy. All
+ * value modifiers are hidden inside the combobox popup and only
+ * the color is shown if not open. This combines the clarity of the
+ * popup with the ease of use of just using the space for modifiers.
+ *
+ * Other instances are for example time and especially date picker,
+ * which only show the currently activated time/data and hide the
+ * selection logic inside the combobox popup.
+ */
+ static float chart_selection = 8.0f;
+ static int current_weapon = 0;
+ static int check_values[5];
+ static float position[3];
+ static struct nk_color combo_color = {130, 50, 50, 255};
+ static struct nk_color combo_color2 = {130, 180, 50, 255};
+ static size_t prog_a = 20, prog_b = 40, prog_c = 10, prog_d = 90;
+ static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"};
+
+ char buffer[64];
+ size_t sum = 0;
+
+ /* default combobox */
+ nk_layout_row_static(ctx, 25, 200, 1);
+ current_weapon = nk_combo(ctx, weapons, LEN(weapons), current_weapon, 25, nk_vec2(200,200));
+
+ /* slider color combobox */
+ if (nk_combo_begin_color(ctx, combo_color, nk_vec2(200,200))) {
+ float ratios[] = {0.15f, 0.85f};
+ nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratios);
+ nk_label(ctx, "R:", NK_TEXT_LEFT);
+ combo_color.r = (nk_byte)nk_slide_int(ctx, 0, combo_color.r, 255, 5);
+ nk_label(ctx, "G:", NK_TEXT_LEFT);
+ combo_color.g = (nk_byte)nk_slide_int(ctx, 0, combo_color.g, 255, 5);
+ nk_label(ctx, "B:", NK_TEXT_LEFT);
+ combo_color.b = (nk_byte)nk_slide_int(ctx, 0, combo_color.b, 255, 5);
+ nk_label(ctx, "A:", NK_TEXT_LEFT);
+ combo_color.a = (nk_byte)nk_slide_int(ctx, 0, combo_color.a , 255, 5);
+ nk_combo_end(ctx);
+ }
+
+ /* complex color combobox */
+ if (nk_combo_begin_color(ctx, combo_color2, nk_vec2(200,400))) {
+ enum color_mode {COL_RGB, COL_HSV};
+ static int col_mode = COL_RGB;
+ #ifndef DEMO_DO_NOT_USE_COLOR_PICKER
+ nk_layout_row_dynamic(ctx, 120, 1);
+ combo_color2 = nk_color_picker(ctx, combo_color2, NK_RGBA);
+ #endif
+
+ nk_layout_row_dynamic(ctx, 25, 2);
+ col_mode = nk_option_label(ctx, "RGB", col_mode == COL_RGB) ? COL_RGB : col_mode;
+ col_mode = nk_option_label(ctx, "HSV", col_mode == COL_HSV) ? COL_HSV : col_mode;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (col_mode == COL_RGB) {
+ combo_color2.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, combo_color2.r, 255, 1,1);
+ combo_color2.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, combo_color2.g, 255, 1,1);
+ combo_color2.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, combo_color2.b, 255, 1,1);
+ combo_color2.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, combo_color2.a, 255, 1,1);
+ } else {
+ nk_byte tmp[4];
+ nk_color_hsva_bv(tmp, combo_color2);
+ tmp[0] = (nk_byte)nk_propertyi(ctx, "#H:", 0, tmp[0], 255, 1,1);
+ tmp[1] = (nk_byte)nk_propertyi(ctx, "#S:", 0, tmp[1], 255, 1,1);
+ tmp[2] = (nk_byte)nk_propertyi(ctx, "#V:", 0, tmp[2], 255, 1,1);
+ tmp[3] = (nk_byte)nk_propertyi(ctx, "#A:", 0, tmp[3], 255, 1,1);
+ combo_color2 = nk_hsva_bv(tmp);
+ }
+ nk_combo_end(ctx);
+ }
+
+ /* progressbar combobox */
+ sum = prog_a + prog_b + prog_c + prog_d;
+ sprintf(buffer, "%lu", sum);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_progress(ctx, &prog_a, 100, NK_MODIFIABLE);
+ nk_progress(ctx, &prog_b, 100, NK_MODIFIABLE);
+ nk_progress(ctx, &prog_c, 100, NK_MODIFIABLE);
+ nk_progress(ctx, &prog_d, 100, NK_MODIFIABLE);
+ nk_combo_end(ctx);
+ }
+
+ /* checkbox combobox */
+ sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]);
+ sprintf(buffer, "%lu", sum);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_checkbox_label(ctx, weapons[0], &check_values[0]);
+ nk_checkbox_label(ctx, weapons[1], &check_values[1]);
+ nk_checkbox_label(ctx, weapons[2], &check_values[2]);
+ nk_checkbox_label(ctx, weapons[3], &check_values[3]);
+ nk_combo_end(ctx);
+ }
+
+ /* complex text combobox */
+ sprintf(buffer, "%.2f, %.2f, %.2f", position[0], position[1],position[2]);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_float(ctx, "#X:", -1024.0f, &position[0], 1024.0f, 1,0.5f);
+ nk_property_float(ctx, "#Y:", -1024.0f, &position[1], 1024.0f, 1,0.5f);
+ nk_property_float(ctx, "#Z:", -1024.0f, &position[2], 1024.0f, 1,0.5f);
+ nk_combo_end(ctx);
+ }
+
+ /* chart combobox */
+ sprintf(buffer, "%.1f", chart_selection);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) {
+ size_t i = 0;
+ static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f};
+ nk_layout_row_dynamic(ctx, 150, 1);
+ nk_chart_begin(ctx, NK_CHART_COLUMN, LEN(values), 0, 50);
+ for (i = 0; i < LEN(values); ++i) {
+ nk_flags res = nk_chart_push(ctx, values[i]);
+ if (res & NK_CHART_CLICKED) {
+ chart_selection = values[i];
+ nk_combo_close(ctx);
+ }
+ }
+ nk_chart_end(ctx);
+ nk_combo_end(ctx);
+ }
+
+ {
+ static int time_selected = 0;
+ static int date_selected = 0;
+ static struct tm sel_time;
+ static struct tm sel_date;
+ if (!time_selected || !date_selected) {
+ /* keep time and date updated if nothing is selected */
+ time_t cur_time = time(0);
+ struct tm *n = localtime(&cur_time);
+ if (!time_selected)
+ memcpy(&sel_time, n, sizeof(struct tm));
+ if (!date_selected)
+ memcpy(&sel_date, n, sizeof(struct tm));
+ }
+
+ /* time combobox */
+ sprintf(buffer, "%02d:%02d:%02d", sel_time.tm_hour, sel_time.tm_min, sel_time.tm_sec);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) {
+ time_selected = 1;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ sel_time.tm_sec = nk_propertyi(ctx, "#S:", 0, sel_time.tm_sec, 60, 1, 1);
+ sel_time.tm_min = nk_propertyi(ctx, "#M:", 0, sel_time.tm_min, 60, 1, 1);
+ sel_time.tm_hour = nk_propertyi(ctx, "#H:", 0, sel_time.tm_hour, 23, 1, 1);
+ nk_combo_end(ctx);
+ }
+
+ /* date combobox */
+ sprintf(buffer, "%02d-%02d-%02d", sel_date.tm_mday, sel_date.tm_mon+1, sel_date.tm_year+1900);
+ if (nk_combo_begin_label(ctx, buffer, nk_vec2(350,400)))
+ {
+ int i = 0;
+ const char *month[] = {"January", "February", "March", "Apil", "May", "June", "July", "August", "September", "Ocotober", "November", "December"};
+ const char *week_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
+ const int month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+ int year = sel_date.tm_year+1900;
+ int leap_year = (!(year % 4) && ((year % 100))) || !(year % 400);
+ int days = (sel_date.tm_mon == 1) ?
+ month_days[sel_date.tm_mon] + leap_year:
+ month_days[sel_date.tm_mon];
+
+ /* header with month and year */
+ date_selected = 1;
+ nk_layout_row_begin(ctx, NK_DYNAMIC, 20, 3);
+ nk_layout_row_push(ctx, 0.05f);
+ if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT)) {
+ if (sel_date.tm_mon == 0) {
+ sel_date.tm_mon = 11;
+ sel_date.tm_year = MAX(0, sel_date.tm_year-1);
+ } else sel_date.tm_mon--;
+ }
+ nk_layout_row_push(ctx, 0.9f);
+ sprintf(buffer, "%s %d", month[sel_date.tm_mon], year);
+ nk_label(ctx, buffer, NK_TEXT_CENTERED);
+ nk_layout_row_push(ctx, 0.05f);
+ if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT)) {
+ if (sel_date.tm_mon == 11) {
+ sel_date.tm_mon = 0;
+ sel_date.tm_year++;
+ } else sel_date.tm_mon++;
+ }
+ nk_layout_row_end(ctx);
+
+ /* good old week day formula (double because precision) */
+ {int year_n = (sel_date.tm_mon < 2) ? year-1: year;
+ int y = year_n % 100;
+ int c = year_n / 100;
+ int y4 = (int)((float)y / 4);
+ int c4 = (int)((float)c / 4);
+ int m = (int)(2.6 * (double)(((sel_date.tm_mon + 10) % 12) + 1) - 0.2);
+ int week_day = (((1 + m + y + y4 + c4 - 2 * c) % 7) + 7) % 7;
+
+ /* weekdays */
+ nk_layout_row_dynamic(ctx, 35, 7);
+ for (i = 0; i < (int)LEN(week_days); ++i)
+ nk_label(ctx, week_days[i], NK_TEXT_CENTERED);
+
+ /* days */
+ if (week_day > 0) nk_spacing(ctx, week_day);
+ for (i = 1; i <= days; ++i) {
+ sprintf(buffer, "%d", i);
+ if (nk_button_label(ctx, buffer)) {
+ sel_date.tm_mday = i;
+ nk_combo_close(ctx);
+ }
+ }}
+ nk_combo_end(ctx);
+ }
+ }
+
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Input", NK_MINIMIZED))
+ {
+ static const float ratio[] = {120, 150};
+ static char field_buffer[64];
+ static char text[9][64];
+ static int text_len[9];
+ static char box_buffer[512];
+ static int field_len;
+ static int box_len;
+ nk_flags active;
+
+ nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+ nk_label(ctx, "Default:", NK_TEXT_LEFT);
+
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[0], &text_len[0], 64, nk_filter_default);
+ nk_label(ctx, "Int:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[1], &text_len[1], 64, nk_filter_decimal);
+ nk_label(ctx, "Float:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[2], &text_len[2], 64, nk_filter_float);
+ nk_label(ctx, "Hex:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[4], &text_len[4], 64, nk_filter_hex);
+ nk_label(ctx, "Octal:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[5], &text_len[5], 64, nk_filter_oct);
+ nk_label(ctx, "Binary:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[6], &text_len[6], 64, nk_filter_binary);
+
+ nk_label(ctx, "Password:", NK_TEXT_LEFT);
+ {
+ int i = 0;
+ int old_len = text_len[8];
+ char buffer[64];
+ for (i = 0; i < text_len[8]; ++i) buffer[i] = '*';
+ nk_edit_string(ctx, NK_EDIT_FIELD, buffer, &text_len[8], 64, nk_filter_default);
+ if (old_len < text_len[8])
+ memcpy(&text[8][old_len], &buffer[old_len], (nk_size)(text_len[8] - old_len));
+ }
+
+ nk_label(ctx, "Field:", NK_TEXT_LEFT);
+ nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);
+
+ nk_label(ctx, "Box:", NK_TEXT_LEFT);
+ nk_layout_row_static(ctx, 180, 278, 1);
+ nk_edit_string(ctx, NK_EDIT_BOX, box_buffer, &box_len, 512, nk_filter_default);
+
+ nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);
+ active = nk_edit_string(ctx, NK_EDIT_FIELD|NK_EDIT_SIG_ENTER, text[7], &text_len[7], 64, nk_filter_ascii);
+ if (nk_button_label(ctx, "Submit") ||
+ (active & NK_EDIT_COMMITED))
+ {
+ text[7][text_len[7]] = '\n';
+ text_len[7]++;
+ memcpy(&box_buffer[box_len], &text[7], (nk_size)text_len[7]);
+ box_len += text_len[7];
+ text_len[7] = 0;
+ }
+ nk_layout_row_end(ctx);
+ nk_tree_pop(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_TAB, "Chart", NK_MINIMIZED))
+ {
+ /* Chart Widgets
+ * This library has two different rather simple charts. The line and the
+ * column chart. Both provide a simple way of visualizing values and
+ * have a retained mode and immediate mode API version. For the retain
+ * mode version `nk_plot` and `nk_plot_function` you either provide
+ * an array or a callback to call to handle drawing the graph.
+ * For the immediate mode version you start by calling `nk_chart_begin`
+ * and need to provide min and max values for scaling on the Y-axis.
+ * and then call `nk_chart_push` to push values into the chart.
+ * Finally `nk_chart_end` needs to be called to end the process. */
+ float id = 0;
+ static int col_index = -1;
+ static int line_index = -1;
+ float step = (2*3.141592654f) / 32;
+
+ int i;
+ int index = -1;
+ struct nk_rect bounds;
+
+ /* line chart */
+ id = 0;
+ index = -1;
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f)) {
+ for (i = 0; i < 32; ++i) {
+ nk_flags res = nk_chart_push(ctx, (float)cos(id));
+ if (res & NK_CHART_HOVERING)
+ index = (int)i;
+ if (res & NK_CHART_CLICKED)
+ line_index = (int)i;
+ id += step;
+ }
+ nk_chart_end(ctx);
+ }
+
+ if (index != -1) {
+ char buffer[NK_MAX_NUMBER_BUFFER];
+ float val = (float)cos((float)index*step);
+ sprintf(buffer, "Value: %.2f", val);
+ nk_tooltip(ctx, buffer);
+ }
+ if (line_index != -1) {
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)cos((float)index*step));
+ }
+
+ /* column chart */
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) {
+ for (i = 0; i < 32; ++i) {
+ nk_flags res = nk_chart_push(ctx, (float)fabs(sin(id)));
+ if (res & NK_CHART_HOVERING)
+ index = (int)i;
+ if (res & NK_CHART_CLICKED)
+ col_index = (int)i;
+ id += step;
+ }
+ nk_chart_end(ctx);
+ }
+ if (index != -1) {
+ char buffer[NK_MAX_NUMBER_BUFFER];
+ sprintf(buffer, "Value: %.2f", (float)fabs(sin(step * (float)index)));
+ nk_tooltip(ctx, buffer);
+ }
+ if (col_index != -1) {
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_labelf(ctx, NK_TEXT_LEFT, "Selected value: %.2f", (float)fabs(sin(step * (float)col_index)));
+ }
+
+ /* mixed chart */
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);
+ nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);
+ for (id = 0, i = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ nk_chart_push_slot(ctx, (float)sin(id), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+
+ /* mixed colored chart */
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f);
+ for (id = 0, i = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ nk_chart_push_slot(ctx, (float)sin(id), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_TAB, "Popup", NK_MINIMIZED))
+ {
+ static struct nk_color color = {255,0,0, 255};
+ static int select[4];
+ static int popup_active;
+ const struct nk_input *in = &ctx->input;
+ struct nk_rect bounds;
+
+ /* menu contextual */
+ nk_layout_row_static(ctx, 30, 150, 1);
+ bounds = nk_widget_bounds(ctx);
+ nk_label(ctx, "Right click me for menu", NK_TEXT_LEFT);
+
+ if (nk_contextual_begin(ctx, 0, nk_vec2(100, 300), bounds)) {
+ static size_t prog = 40;
+ static int slider = 10;
+
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_checkbox_label(ctx, "Menu", &show_menu);
+ nk_progress(ctx, &prog, 100, NK_MODIFIABLE);
+ nk_slider_int(ctx, 0, &slider, 16, 1);
+ if (nk_contextual_item_label(ctx, "About", NK_TEXT_CENTERED))
+ show_app_about = nk_true;
+ nk_selectable_label(ctx, select[0]?"Unselect":"Select", NK_TEXT_LEFT, &select[0]);
+ nk_selectable_label(ctx, select[1]?"Unselect":"Select", NK_TEXT_LEFT, &select[1]);
+ nk_selectable_label(ctx, select[2]?"Unselect":"Select", NK_TEXT_LEFT, &select[2]);
+ nk_selectable_label(ctx, select[3]?"Unselect":"Select", NK_TEXT_LEFT, &select[3]);
+ nk_contextual_end(ctx);
+ }
+
+ /* color contextual */
+ nk_layout_row_begin(ctx, NK_STATIC, 30, 2);
+ nk_layout_row_push(ctx, 100);
+ nk_label(ctx, "Right Click here:", NK_TEXT_LEFT);
+ nk_layout_row_push(ctx, 50);
+ bounds = nk_widget_bounds(ctx);
+ nk_button_color(ctx, color);
+ nk_layout_row_end(ctx);
+
+ if (nk_contextual_begin(ctx, 0, nk_vec2(350, 60), bounds)) {
+ nk_layout_row_dynamic(ctx, 30, 4);
+ color.r = (nk_byte)nk_propertyi(ctx, "#r", 0, color.r, 255, 1, 1);
+ color.g = (nk_byte)nk_propertyi(ctx, "#g", 0, color.g, 255, 1, 1);
+ color.b = (nk_byte)nk_propertyi(ctx, "#b", 0, color.b, 255, 1, 1);
+ color.a = (nk_byte)nk_propertyi(ctx, "#a", 0, color.a, 255, 1, 1);
+ nk_contextual_end(ctx);
+ }
+
+ /* popup */
+ nk_layout_row_begin(ctx, NK_STATIC, 30, 2);
+ nk_layout_row_push(ctx, 100);
+ nk_label(ctx, "Popup:", NK_TEXT_LEFT);
+ nk_layout_row_push(ctx, 50);
+ if (nk_button_label(ctx, "Popup"))
+ popup_active = 1;
+ nk_layout_row_end(ctx);
+
+ if (popup_active)
+ {
+ static struct nk_rect s = {20, 100, 220, 90};
+ if (nk_popup_begin(ctx, NK_POPUP_STATIC, "Error", 0, s))
+ {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_label(ctx, "A terrible error as occured", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 2);
+ if (nk_button_label(ctx, "OK")) {
+ popup_active = 0;
+ nk_popup_close(ctx);
+ }
+ if (nk_button_label(ctx, "Cancel")) {
+ popup_active = 0;
+ nk_popup_close(ctx);
+ }
+ nk_popup_end(ctx);
+ } else popup_active = nk_false;
+ }
+
+ /* tooltip */
+ nk_layout_row_static(ctx, 30, 150, 1);
+ bounds = nk_widget_bounds(ctx);
+ nk_label(ctx, "Hover me for tooltip", NK_TEXT_LEFT);
+ if (nk_input_is_mouse_hovering_rect(in, bounds))
+ nk_tooltip(ctx, "This is a tooltip");
+
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_TAB, "Layout", NK_MINIMIZED))
+ {
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Widget", NK_MINIMIZED))
+ {
+ float ratio_two[] = {0.2f, 0.6f, 0.2f};
+ float width_two[] = {100, 200, 50};
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Dynamic fixed column layout with generated position and size:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 30, 3);
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "static fixed column layout with generated position and size:", NK_TEXT_LEFT);
+ nk_layout_row_static(ctx, 30, 100, 3);
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Dynamic array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT);
+ nk_layout_row(ctx, NK_DYNAMIC, 30, 3, ratio_two);
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Static array-based custom column layout with generated position and custom size:",NK_TEXT_LEFT );
+ nk_layout_row(ctx, NK_STATIC, 30, 3, width_two);
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+ nk_button_label(ctx, "button");
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Dynamic immediate mode custom column layout with generated position and custom size:",NK_TEXT_LEFT);
+ nk_layout_row_begin(ctx, NK_DYNAMIC, 30, 3);
+ nk_layout_row_push(ctx, 0.2f);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 0.6f);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 0.2f);
+ nk_button_label(ctx, "button");
+ nk_layout_row_end(ctx);
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Static immediate mode custom column layout with generated position and custom size:", NK_TEXT_LEFT);
+ nk_layout_row_begin(ctx, NK_STATIC, 30, 3);
+ nk_layout_row_push(ctx, 100);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 200);
+ nk_button_label(ctx, "button");
+ nk_layout_row_push(ctx, 50);
+ nk_button_label(ctx, "button");
+ nk_layout_row_end(ctx);
+
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_label(ctx, "Static free space with custom position and custom size:", NK_TEXT_LEFT);
+ nk_layout_space_begin(ctx, NK_STATIC, 120, 4);
+ nk_layout_space_push(ctx, nk_rect(100, 0, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_push(ctx, nk_rect(0, 15, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_push(ctx, nk_rect(200, 15, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_push(ctx, nk_rect(100, 30, 100, 30));
+ nk_button_label(ctx, "button");
+ nk_layout_space_end(ctx);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Group", NK_MINIMIZED))
+ {
+ static int group_titlebar = nk_false;
+ static int group_border = nk_true;
+ static int group_no_scrollbar = nk_false;
+ static int group_width = 320;
+ static int group_height = 200;
+
+ nk_flags group_flags = 0;
+ if (group_border) group_flags |= NK_WINDOW_BORDER;
+ if (group_no_scrollbar) group_flags |= NK_WINDOW_NO_SCROLLBAR;
+ if (group_titlebar) group_flags |= NK_WINDOW_TITLE;
+
+ nk_layout_row_dynamic(ctx, 30, 3);
+ nk_checkbox_label(ctx, "Titlebar", &group_titlebar);
+ nk_checkbox_label(ctx, "Border", &group_border);
+ nk_checkbox_label(ctx, "No Scrollbar", &group_no_scrollbar);
+
+ nk_layout_row_begin(ctx, NK_STATIC, 22, 2);
+ nk_layout_row_push(ctx, 50);
+ nk_label(ctx, "size:", NK_TEXT_LEFT);
+ nk_layout_row_push(ctx, 130);
+ nk_property_int(ctx, "#Width:", 100, &group_width, 500, 10, 1);
+ nk_layout_row_push(ctx, 130);
+ nk_property_int(ctx, "#Height:", 100, &group_height, 500, 10, 1);
+ nk_layout_row_end(ctx);
+
+ nk_layout_row_static(ctx, (float)group_height, group_width, 2);
+ if (nk_group_begin(ctx, "Group", group_flags)) {
+ int i = 0;
+ static int selected[16];
+ nk_layout_row_static(ctx, 18, 100, 1);
+ for (i = 0; i < 16; ++i)
+ nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+ nk_group_end(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Notebook", NK_MINIMIZED))
+ {
+ static int current_tab = 0;
+ struct nk_vec2 item_padding;
+ struct nk_rect bounds;
+ float step = (2*3.141592654f) / 32;
+ enum chart_type {CHART_LINE, CHART_HISTO, CHART_MIXED};
+ const char *names[] = {"Lines", "Columns", "Mixed"};
+ float id = 0;
+ int i;
+
+ /* Header */
+ nk_style_push_vec2(ctx, &ctx->style.window.spacing, nk_vec2(0,0));
+ nk_style_push_float(ctx, &ctx->style.button.rounding, 0);
+ nk_layout_row_begin(ctx, NK_STATIC, 20, 3);
+ for (i = 0; i < 3; ++i) {
+ /* make sure button perfectly fits text */
+ const struct nk_user_font *f = ctx->style.font;
+ float text_width = f->width(f->userdata, f->height, names[i], nk_strlen(names[i]));
+ float widget_width = text_width + 3 * ctx->style.button.padding.x;
+ nk_layout_row_push(ctx, widget_width);
+ if (current_tab == i) {
+ /* active tab gets highlighted */
+ struct nk_style_item button_color = ctx->style.button.normal;
+ ctx->style.button.normal = ctx->style.button.active;
+ current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;
+ ctx->style.button.normal = button_color;
+ } else current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;
+ }
+ nk_style_pop_float(ctx);
+
+ /* Body */
+ nk_layout_row_dynamic(ctx, 140, 1);
+ if (nk_group_begin(ctx, "Notebook", NK_WINDOW_BORDER))
+ {
+ nk_style_pop_vec2(ctx);
+ switch (current_tab) {
+ case CHART_LINE:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)cos(id), 1);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ case CHART_HISTO:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_COLUMN, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ case CHART_MIXED:
+ nk_layout_row_dynamic(ctx, 100, 1);
+ bounds = nk_widget_bounds(ctx);
+ if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {
+ nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);
+ nk_chart_add_slot_colored(ctx, NK_CHART_COLUMN, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, 0.0f, 1.0f);
+ for (i = 0, id = 0; i < 32; ++i) {
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);
+ nk_chart_push_slot(ctx, (float)fabs(cos(id)), 1);
+ nk_chart_push_slot(ctx, (float)fabs(sin(id)), 2);
+ id += step;
+ }
+ }
+ nk_chart_end(ctx);
+ break;
+ }
+ nk_group_end(ctx);
+ } else nk_style_pop_vec2(ctx);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Simple", NK_MINIMIZED))
+ {
+ nk_layout_row_dynamic(ctx, 300, 2);
+ if (nk_group_begin(ctx, "Group_Without_Border", 0)) {
+ int i = 0;
+ char buffer[64];
+ nk_layout_row_static(ctx, 18, 150, 1);
+ for (i = 0; i < 64; ++i) {
+ sprintf(buffer, "0x%02x", i);
+ nk_labelf(ctx, NK_TEXT_LEFT, "%s: scrollable region", buffer);
+ }
+ nk_group_end(ctx);
+ }
+ if (nk_group_begin(ctx, "Group_With_Border", NK_WINDOW_BORDER)) {
+ int i = 0;
+ char buffer[64];
+ nk_layout_row_dynamic(ctx, 25, 2);
+ for (i = 0; i < 64; ++i) {
+ sprintf(buffer, "%08d", ((((i%7)*10)^32))+(64+(i%2)*2));
+ nk_button_label(ctx, buffer);
+ }
+ nk_group_end(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Complex", NK_MINIMIZED))
+ {
+ int i;
+ nk_layout_space_begin(ctx, NK_STATIC, 500, 64);
+ nk_layout_space_push(ctx, nk_rect(0,0,150,500));
+ if (nk_group_begin(ctx, "Group_left", NK_WINDOW_BORDER)) {
+ static int selected[32];
+ nk_layout_row_static(ctx, 18, 100, 1);
+ for (i = 0; i < 32; ++i)
+ nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(160,0,150,240));
+ if (nk_group_begin(ctx, "Group_top", NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(160,250,150,250));
+ if (nk_group_begin(ctx, "Group_buttom", NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(320,0,150,150));
+ if (nk_group_begin(ctx, "Group_right_top", NK_WINDOW_BORDER)) {
+ static int selected[4];
+ nk_layout_row_static(ctx, 18, 100, 1);
+ for (i = 0; i < 4; ++i)
+ nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(320,160,150,150));
+ if (nk_group_begin(ctx, "Group_right_center", NK_WINDOW_BORDER)) {
+ static int selected[4];
+ nk_layout_row_static(ctx, 18, 100, 1);
+ for (i = 0; i < 4; ++i)
+ nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+ nk_group_end(ctx);
+ }
+
+ nk_layout_space_push(ctx, nk_rect(320,320,150,150));
+ if (nk_group_begin(ctx, "Group_right_bottom", NK_WINDOW_BORDER)) {
+ static int selected[4];
+ nk_layout_row_static(ctx, 18, 100, 1);
+ for (i = 0; i < 4; ++i)
+ nk_selectable_label(ctx, (selected[i]) ? "Selected": "Unselected", NK_TEXT_CENTERED, &selected[i]);
+ nk_group_end(ctx);
+ }
+ nk_layout_space_end(ctx);
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Splitter", NK_MINIMIZED))
+ {
+ const struct nk_input *in = &ctx->input;
+ nk_layout_row_static(ctx, 20, 320, 1);
+ nk_label(ctx, "Use slider and spinner to change tile size", NK_TEXT_LEFT);
+ nk_label(ctx, "Drag the space between tiles to change tile ratio", NK_TEXT_LEFT);
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Vertical", NK_MINIMIZED))
+ {
+ static float a = 100, b = 100, c = 100;
+ struct nk_rect bounds;
+
+ float row_layout[5];
+ row_layout[0] = a;
+ row_layout[1] = 8;
+ row_layout[2] = b;
+ row_layout[3] = 8;
+ row_layout[4] = c;
+
+ /* header */
+ nk_layout_row_static(ctx, 30, 100, 2);
+ nk_label(ctx, "left:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
+
+ nk_label(ctx, "middle:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
+
+ nk_label(ctx, "right:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
+
+ /* tiles */
+ nk_layout_row(ctx, NK_STATIC, 200, 5, row_layout);
+
+ /* left space */
+ if (nk_group_begin(ctx, "left", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ /* scaler */
+ bounds = nk_widget_bounds(ctx);
+ nk_spacing(ctx, 1);
+ if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+ nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+ {
+ a = row_layout[0] + in->mouse.delta.x;
+ b = row_layout[2] - in->mouse.delta.x;
+ }
+
+ /* middle space */
+ if (nk_group_begin(ctx, "center", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ /* scaler */
+ bounds = nk_widget_bounds(ctx);
+ nk_spacing(ctx, 1);
+ if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+ nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+ {
+ b = (row_layout[2] + in->mouse.delta.x);
+ c = (row_layout[4] - in->mouse.delta.x);
+ }
+
+ /* right space */
+ if (nk_group_begin(ctx, "right", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ nk_tree_pop(ctx);
+ }
+
+ if (nk_tree_push(ctx, NK_TREE_NODE, "Horizontal", NK_MINIMIZED))
+ {
+ static float a = 100, b = 100, c = 100;
+ struct nk_rect bounds;
+
+ /* header */
+ nk_layout_row_static(ctx, 30, 100, 2);
+ nk_label(ctx, "top:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);
+
+ nk_label(ctx, "middle:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);
+
+ nk_label(ctx, "bottom:", NK_TEXT_LEFT);
+ nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);
+
+ /* top space */
+ nk_layout_row_dynamic(ctx, a, 1);
+ if (nk_group_begin(ctx, "top", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ /* scaler */
+ nk_layout_row_dynamic(ctx, 8, 1);
+ bounds = nk_widget_bounds(ctx);
+ nk_spacing(ctx, 1);
+ if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+ nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+ {
+ a = a + in->mouse.delta.y;
+ b = b - in->mouse.delta.y;
+ }
+
+ /* middle space */
+ nk_layout_row_dynamic(ctx, b, 1);
+ if (nk_group_begin(ctx, "middle", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+
+ {
+ /* scaler */
+ nk_layout_row_dynamic(ctx, 8, 1);
+ bounds = nk_widget_bounds(ctx);
+ if ((nk_input_is_mouse_hovering_rect(in, bounds) ||
+ nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_LEFT))
+ {
+ b = b + in->mouse.delta.y;
+ c = c - in->mouse.delta.y;
+ }
+ }
+
+ /* bottom space */
+ nk_layout_row_dynamic(ctx, c, 1);
+ if (nk_group_begin(ctx, "bottom", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_dynamic(ctx, 25, 3);
+ nk_button_label(ctx, "#FFAA");
+ nk_button_label(ctx, "#FFBB");
+ nk_button_label(ctx, "#FFCC");
+ nk_button_label(ctx, "#FFDD");
+ nk_button_label(ctx, "#FFEE");
+ nk_button_label(ctx, "#FFFF");
+ nk_group_end(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+ nk_tree_pop(ctx);
+ }
+ }
+ nk_end(ctx);
+ return !nk_window_is_closed(ctx, "Overview");
+}
+
diff --git a/nuklear/demo/sdl_opengl2/Makefile b/nuklear/demo/sdl_opengl2/Makefile
new file mode 100644
index 0000000..2c85a6e
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lSDL2 -framework OpenGL -lm
+ else
+ LIBS = -lSDL2 -lGL -lm -lGLU
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/sdl_opengl2/main.c b/nuklear/demo/sdl_opengl2/main.c
new file mode 100644
index 0000000..0d96551
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/main.c
@@ -0,0 +1,181 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SDL_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sdl_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(int argc, char* argv[])
+{
+ /* Platform */
+ SDL_Window *win;
+ SDL_GLContext glContext;
+ struct nk_color background;
+ int win_width, win_height;
+ int running = 1;
+
+ /* GUI */
+ struct nk_context *ctx;
+
+ /* SDL setup */
+ SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
+ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+ win = SDL_CreateWindow("Demo",
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);
+ glContext = SDL_GL_CreateContext(win);
+ SDL_GetWindowSize(win, &win_width, &win_height);
+
+ /* GUI */
+ ctx = nk_sdl_init(win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_sdl_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_sdl_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &roboto->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ SDL_Event evt;
+ nk_input_begin(ctx);
+ while (SDL_PollEvent(&evt)) {
+ if (evt.type == SDL_QUIT) goto cleanup;
+ nk_sdl_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 210, 250),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ SDL_GetWindowSize(win, &win_width, &win_height);
+ glViewport(0, 0, win_width, win_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
+ SDL_GL_SwapWindow(win);}
+ }
+
+cleanup:
+ nk_sdl_shutdown();
+ SDL_GL_DeleteContext(glContext);
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return 0;
+}
+
diff --git a/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h b/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h
new file mode 100644
index 0000000..45c5970
--- /dev/null
+++ b/nuklear/demo/sdl_opengl2/nuklear_sdl_gl2.h
@@ -0,0 +1,342 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GL2_H_
+#define NK_SDL_GL2_H_
+
+#include <SDL2/SDL.h>
+NK_API struct nk_context* nk_sdl_init(SDL_Window *win);
+NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_sdl_font_stash_end(void);
+NK_API int nk_sdl_handle_event(SDL_Event *evt);
+NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_sdl_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GL2_IMPLEMENTATION
+
+struct nk_sdl_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+struct nk_sdl_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_sdl {
+ SDL_Window *win;
+ struct nk_sdl_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sdl;
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_sdl_device *dev = &sdl.ogl;
+ int width, height;
+ int display_width, display_height;
+ struct nk_vec2 scale;
+
+ SDL_GetWindowSize(sdl.win, &width, &height);
+ SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)display_width,(GLsizei)display_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_sdl_vertex);
+ size_t vp = offsetof(struct nk_sdl_vertex, position);
+ size_t vt = offsetof(struct nk_sdl_vertex, uv);
+ size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill converting configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sdl_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&sdl.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+}
+
+static void
+nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ const char *text = SDL_GetClipboardText();
+ if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+}
+
+static void
+nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ SDL_SetClipboardText(str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+ sdl.win = win;
+ nk_init_default(&sdl.ctx, 0);
+ sdl.ctx.clip.copy = nk_sdl_clipbard_copy;
+ sdl.ctx.clip.paste = nk_sdl_clipbard_paste;
+ sdl.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_buffer_init_default(&sdl.ogl.cmds);
+ return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&sdl.atlas);
+ nk_font_atlas_begin(&sdl.atlas);
+ *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_sdl_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null);
+ if (sdl.atlas.default_font)
+ nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+ struct nk_context *ctx = &sdl.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ SDL_SetRelativeMouseMode(SDL_TRUE);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ SDL_SetRelativeMouseMode(SDL_FALSE);
+ SDL_WarpMouseInWindow(sdl.win, x, y);
+ ctx->input.mouse.ungrab = 0;
+ }
+ if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) {
+ /* key events */
+ int down = evt->type == SDL_KEYDOWN;
+ const Uint8* state = SDL_GetKeyboardState(0);
+ SDL_Keycode sym = evt->key.keysym.sym;
+ if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
+ nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (sym == SDLK_DELETE)
+ nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (sym == SDLK_RETURN)
+ nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (sym == SDLK_TAB)
+ nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (sym == SDLK_BACKSPACE)
+ nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (sym == SDLK_HOME) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (sym == SDLK_END) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if (sym == SDLK_PAGEDOWN) {
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ } else if (sym == SDLK_PAGEUP) {
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ } else if (sym == SDLK_z)
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_r)
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_c)
+ nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_v)
+ nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_x)
+ nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_b)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_e)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_UP)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if (sym == SDLK_DOWN)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (sym == SDLK_LEFT) {
+ if (state[SDL_SCANCODE_LCTRL])
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else nk_input_key(ctx, NK_KEY_LEFT, down);
+ } else if (sym == SDLK_RIGHT) {
+ if (state[SDL_SCANCODE_LCTRL])
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else nk_input_key(ctx, NK_KEY_RIGHT, down);
+ } else return 0;
+ return 1;
+ } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
+ /* mouse button */
+ int down = evt->type == SDL_MOUSEBUTTONDOWN;
+ const int x = evt->button.x, y = evt->button.y;
+ if (evt->button.button == SDL_BUTTON_LEFT)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if (evt->button.button == SDL_BUTTON_MIDDLE)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ if (evt->button.button == SDL_BUTTON_RIGHT)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else return 0;
+ return 1;
+ } else if (evt->type == SDL_MOUSEMOTION) {
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ nk_input_scroll(ctx,(float)evt->wheel.y);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ nk_font_atlas_clear(&sdl.atlas);
+ nk_free(&sdl.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif
diff --git a/nuklear/demo/sdl_opengl3/Makefile b/nuklear/demo/sdl_opengl3/Makefile
new file mode 100644
index 0000000..4b8ccf4
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/Makefile
@@ -0,0 +1,25 @@
+# Install
+BIN = demo
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS = -lSDL2 -framework OpenGL -lm -lGLEW
+ else
+ LIBS = -lSDL2 -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)
diff --git a/nuklear/demo/sdl_opengl3/main.c b/nuklear/demo/sdl_opengl3/main.c
new file mode 100644
index 0000000..aee4f82
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/main.c
@@ -0,0 +1,195 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <GL/glew.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SDL_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sdl_gl3.h"
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(int argc, char* argv[])
+{
+ /* Platform */
+ SDL_Window *win;
+ SDL_GLContext glContext;
+ struct nk_color background;
+ int win_width, win_height;
+ int running = 1;
+
+ /* GUI */
+ struct nk_context *ctx;
+
+ /* SDL setup */
+ SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
+ SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
+ SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
+ SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ win = SDL_CreateWindow("Demo",
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);
+ glContext = SDL_GL_CreateContext(win);
+ SDL_GetWindowSize(win, &win_width, &win_height);
+
+ /* OpenGL setup */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ ctx = nk_sdl_init(win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_sdl_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_sdl_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &roboto->handle)*/;}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ SDL_Event evt;
+ nk_input_begin(ctx);
+ while (SDL_PollEvent(&evt)) {
+ if (evt.type == SDL_QUIT) goto cleanup;
+ nk_sdl_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ nk_menubar_begin(ctx);
+ nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
+ nk_layout_row_push(ctx, 45);
+ if (nk_menu_begin_label(ctx, "FILE", NK_TEXT_LEFT, nk_vec2(120, 200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_menu_item_label(ctx, "OPEN", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "CLOSE", NK_TEXT_LEFT);
+ nk_menu_end(ctx);
+ }
+ nk_layout_row_push(ctx, 45);
+ if (nk_menu_begin_label(ctx, "EDIT", NK_TEXT_LEFT, nk_vec2(120, 200))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ nk_menu_item_label(ctx, "COPY", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "CUT", NK_TEXT_LEFT);
+ nk_menu_item_label(ctx, "PASTE", NK_TEXT_LEFT);
+ nk_menu_end(ctx);
+ }
+ nk_layout_row_end(ctx);
+ nk_menubar_end(ctx);
+
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ SDL_GetWindowSize(win, &win_width, &win_height);
+ glViewport(0, 0, win_width, win_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
+ SDL_GL_SwapWindow(win);}
+ }
+
+cleanup:
+ nk_sdl_shutdown();
+ SDL_GL_DeleteContext(glContext);
+ SDL_DestroyWindow(win);
+ SDL_Quit();
+ return 0;
+}
+
diff --git a/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h b/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h
new file mode 100644
index 0000000..17c0899
--- /dev/null
+++ b/nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h
@@ -0,0 +1,437 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SDL_GL3_H_
+#define NK_SDL_GL3_H_
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+NK_API struct nk_context* nk_sdl_init(SDL_Window *win);
+NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_sdl_font_stash_end(void);
+NK_API int nk_sdl_handle_event(SDL_Event *evt);
+NK_API void nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_sdl_shutdown(void);
+NK_API void nk_sdl_device_destroy(void);
+NK_API void nk_sdl_device_create(void);
+
+#endif
+
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_SDL_GL3_IMPLEMENTATION
+
+#include <string.h>
+
+struct nk_sdl_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+struct nk_sdl_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+static struct nk_sdl {
+ SDL_Window *win;
+ struct nk_sdl_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+} sdl;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+NK_API void
+nk_sdl_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ struct nk_sdl_device *dev = &sdl.ogl;
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_sdl_vertex);
+ size_t vp = offsetof(struct nk_sdl_vertex, position);
+ size_t vt = offsetof(struct nk_sdl_vertex, uv);
+ size_t vc = offsetof(struct nk_sdl_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+NK_INTERN void
+nk_sdl_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sdl_device_destroy(void)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ struct nk_sdl_device *dev = &sdl.ogl;
+ int width, height;
+ int display_width, display_height;
+ struct nk_vec2 scale;
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ SDL_GetWindowSize(sdl.win, &width, &height);
+ SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* setup global state */
+ glViewport(0,0,display_width,display_height);
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+ /* load vertices/elements directly into vertex/element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_sdl_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
+ nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
+ nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor((GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&sdl.ctx);
+ }
+
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+static void
+nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+ const char *text = SDL_GetClipboardText();
+ if (text) nk_textedit_paste(edit, text, nk_strlen(text));
+ (void)usr;
+}
+
+static void
+nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len)
+{
+ char *str = 0;
+ (void)usr;
+ if (!len) return;
+ str = (char*)malloc((size_t)len+1);
+ if (!str) return;
+ memcpy(str, text, (size_t)len);
+ str[len] = '\0';
+ SDL_SetClipboardText(str);
+ free(str);
+}
+
+NK_API struct nk_context*
+nk_sdl_init(SDL_Window *win)
+{
+ sdl.win = win;
+ nk_init_default(&sdl.ctx, 0);
+ sdl.ctx.clip.copy = nk_sdl_clipbard_copy;
+ sdl.ctx.clip.paste = nk_sdl_clipbard_paste;
+ sdl.ctx.clip.userdata = nk_handle_ptr(0);
+ nk_sdl_device_create();
+ return &sdl.ctx;
+}
+
+NK_API void
+nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&sdl.atlas);
+ nk_font_atlas_begin(&sdl.atlas);
+ *atlas = &sdl.atlas;
+}
+
+NK_API void
+nk_sdl_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_sdl_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null);
+ if (sdl.atlas.default_font)
+ nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
+
+}
+
+NK_API int
+nk_sdl_handle_event(SDL_Event *evt)
+{
+ struct nk_context *ctx = &sdl.ctx;
+ if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) {
+ /* key events */
+ int down = evt->type == SDL_KEYDOWN;
+ const Uint8* state = SDL_GetKeyboardState(0);
+ SDL_Keycode sym = evt->key.keysym.sym;
+ if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
+ nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (sym == SDLK_DELETE)
+ nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (sym == SDLK_RETURN)
+ nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (sym == SDLK_TAB)
+ nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (sym == SDLK_BACKSPACE)
+ nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (sym == SDLK_HOME) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (sym == SDLK_END) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else if (sym == SDLK_PAGEDOWN) {
+ nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ } else if (sym == SDLK_PAGEUP) {
+ nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ } else if (sym == SDLK_z)
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_r)
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_c)
+ nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_v)
+ nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_x)
+ nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_b)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_e)
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]);
+ else if (sym == SDLK_UP)
+ nk_input_key(ctx, NK_KEY_UP, down);
+ else if (sym == SDLK_DOWN)
+ nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (sym == SDLK_LEFT) {
+ if (state[SDL_SCANCODE_LCTRL])
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else nk_input_key(ctx, NK_KEY_LEFT, down);
+ } else if (sym == SDLK_RIGHT) {
+ if (state[SDL_SCANCODE_LCTRL])
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else nk_input_key(ctx, NK_KEY_RIGHT, down);
+ } else return 0;
+ return 1;
+ } else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
+ /* mouse button */
+ int down = evt->type == SDL_MOUSEBUTTONDOWN;
+ const int x = evt->button.x, y = evt->button.y;
+ if (evt->button.button == SDL_BUTTON_LEFT)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if (evt->button.button == SDL_BUTTON_MIDDLE)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ if (evt->button.button == SDL_BUTTON_RIGHT)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ return 1;
+ } else if (evt->type == SDL_MOUSEMOTION) {
+ if (ctx->input.mouse.grabbed) {
+ int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
+ nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
+ } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
+ return 1;
+ } else if (evt->type == SDL_TEXTINPUT) {
+ nk_glyph glyph;
+ memcpy(glyph, evt->text.text, NK_UTF_SIZE);
+ nk_input_glyph(ctx, glyph);
+ return 1;
+ } else if (evt->type == SDL_MOUSEWHEEL) {
+ nk_input_scroll(ctx,(float)evt->wheel.y);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API
+void nk_sdl_shutdown(void)
+{
+ nk_font_atlas_clear(&sdl.atlas);
+ nk_free(&sdl.ctx);
+ nk_sdl_device_destroy();
+ memset(&sdl, 0, sizeof(sdl));
+}
+
+#endif
diff --git a/nuklear/demo/style.c b/nuklear/demo/style.c
new file mode 100644
index 0000000..8cea152
--- /dev/null
+++ b/nuklear/demo/style.c
@@ -0,0 +1,132 @@
+enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK};
+
+void
+set_style(struct nk_context *ctx, enum theme theme)
+{
+ struct nk_color table[NK_COLOR_COUNT];
+ if (theme == THEME_WHITE) {
+ table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);
+ table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);
+ table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);
+ table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);
+ table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);
+ table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);
+ table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);
+ table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);
+ table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);
+ table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);
+ table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);
+ table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
+ table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);
+ table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);
+ nk_style_from_table(ctx, table);
+ } else if (theme == THEME_RED) {
+ table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215);
+ table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220);
+ table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255);
+ table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255);
+ table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255);
+ table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255);
+ table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255);
+ table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255);
+ table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255);
+ table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255);
+ table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255);
+ table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225);
+ table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255);
+ table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255);
+ table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255);
+ table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
+ table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
+ table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220);
+ nk_style_from_table(ctx, table);
+ } else if (theme == THEME_BLUE) {
+ table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255);
+ table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215);
+ table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220);
+ table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255);
+ table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255);
+ table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255);
+ table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255);
+ table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255);
+ table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255);
+ table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255);
+ table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255);
+ table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255);
+ table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255);
+ table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245);
+ table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255);
+ table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255);
+ table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255);
+ table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225);
+ table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255);
+ table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255);
+ table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255);
+ table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255);
+ table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
+ table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
+ table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255);
+ nk_style_from_table(ctx, table);
+ } else if (theme == THEME_DARK) {
+ table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
+ table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215);
+ table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
+ table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
+ table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255);
+ table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);
+ table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);
+ table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);
+ table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);
+ table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);
+ table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);
+ table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);
+ table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
+ table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
+ table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);
+ table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);
+ table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);
+ table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
+ table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
+ table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
+ table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);
+ nk_style_from_table(ctx, table);
+ } else {
+ nk_style_default(ctx);
+ }
+}
+
+
diff --git a/nuklear/demo/x11/Makefile b/nuklear/demo/x11/Makefile
new file mode 100644
index 0000000..0570089
--- /dev/null
+++ b/nuklear/demo/x11/Makefile
@@ -0,0 +1,13 @@
+# Install
+BIN = zahnrad
+
+# Flags
+CFLAGS = -std=c89 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) -lX11 -lm
diff --git a/nuklear/demo/x11/main.c b/nuklear/demo/x11/main.c
new file mode 100644
index 0000000..8f4b12c
--- /dev/null
+++ b/nuklear/demo/x11/main.c
@@ -0,0 +1,203 @@
+/* nuklear - v1.17 - public domain */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_XLIB_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_xlib.h"
+
+#define DTIME 20
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+typedef struct XWindow XWindow;
+struct XWindow {
+ Display *dpy;
+ Window root;
+ Visual *vis;
+ Colormap cmap;
+ XWindowAttributes attr;
+ XSetWindowAttributes swa;
+ Window win;
+ int screen;
+ XFont *font;
+ unsigned int width;
+ unsigned int height;
+};
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void*
+xcalloc(size_t siz, size_t n)
+{
+ void *ptr = calloc(siz, n);
+ if (!ptr) die("Out of memory\n");
+ return ptr;
+}
+
+static long
+timestamp(void)
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) return 0;
+ return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
+static void
+sleep_for(long t)
+{
+ struct timespec req;
+ const time_t sec = (int)(t/1000);
+ const long ms = t - (sec * 1000);
+ req.tv_sec = sec;
+ req.tv_nsec = ms * 1000000L;
+ while(-1 == nanosleep(&req, &req));
+}
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+#include "../overview.c"
+#include "../node_editor.c"
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+int
+main(void)
+{
+ long dt;
+ long started;
+ int running = 1;
+ XWindow xw;
+ struct nk_context *ctx;
+
+ /* X11 */
+ memset(&xw, 0, sizeof xw);
+ xw.dpy = XOpenDisplay(NULL);
+ if (!xw.dpy) die("Could not open a display; perhaps $DISPLAY is not set?");
+
+ xw.root = DefaultRootWindow(xw.dpy);
+ xw.screen = XDefaultScreen(xw.dpy);
+ xw.vis = XDefaultVisual(xw.dpy, xw.screen);
+ xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
+ xw.swa.colormap = xw.cmap;
+ xw.swa.event_mask =
+ ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPress | ButtonReleaseMask| ButtonMotionMask |
+ Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
+ PointerMotionMask | KeymapStateMask;
+ xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
+ XDefaultDepth(xw.dpy, xw.screen), InputOutput,
+ xw.vis, CWEventMask | CWColormap, &xw.swa);
+ XStoreName(xw.dpy, xw.win, "X11");
+ XMapWindow(xw.dpy, xw.win);
+ XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
+ xw.width = (unsigned int)xw.attr.width;
+ xw.height = (unsigned int)xw.attr.height;
+
+ /* GUI */
+ xw.font = nk_xfont_create(xw.dpy, "fixed");
+ ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height);
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ started = timestamp();
+ nk_input_begin(ctx);
+ while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)){
+ if (XFilterEvent(&evt, xw.win)) continue;
+ nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ overview(ctx);
+ node_editor(ctx);
+ /* ----------------------------------------- */
+
+ /* Draw */
+ XClearWindow(xw.dpy, xw.win);
+ nk_xlib_render(xw.win, nk_rgb(30,30,30));
+ XFlush(xw.dpy);
+
+ /* Timing */
+ dt = timestamp() - started;
+ if (dt < DTIME)
+ sleep_for(DTIME - dt);
+ }
+
+ nk_xfont_del(xw.dpy, xw.font);
+ nk_xlib_shutdown();
+ XUnmapWindow(xw.dpy, xw.win);
+ XFreeColormap(xw.dpy, xw.cmap);
+ XDestroyWindow(xw.dpy, xw.win);
+ XCloseDisplay(xw.dpy);
+ return 0;
+}
+
diff --git a/nuklear/demo/x11/nuklear_xlib.h b/nuklear/demo/x11/nuklear_xlib.h
new file mode 100644
index 0000000..df66d78
--- /dev/null
+++ b/nuklear/demo/x11/nuklear_xlib.h
@@ -0,0 +1,693 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_H_
+#define NK_XLIB_H_
+
+#include <X11/Xlib.h>
+/* Font */
+typedef struct XFont XFont;
+NK_API XFont* nk_xfont_create(Display *dpy, const char *name);
+NK_API void nk_xfont_del(Display *dpy, XFont *font);
+
+NK_API struct nk_context* nk_xlib_init(XFont *font, Display *dpy, int screen, Window root, unsigned int w, unsigned int h);
+NK_API int nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt);
+NK_API void nk_xlib_render(Drawable screen, struct nk_color clear);
+NK_API void nk_xlib_shutdown(void);
+NK_API void nk_xlib_set_font(XFont *font);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_IMPLEMENTATION
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+typedef struct XSurface XSurface;
+struct XFont {
+ int ascent;
+ int descent;
+ int height;
+ XFontSet set;
+ XFontStruct *xfont;
+ struct nk_user_font handle;
+};
+struct XSurface {
+ GC gc;
+ Display *dpy;
+ int screen;
+ Window root;
+ Drawable drawable;
+ unsigned int w, h;
+};
+static struct {
+ struct nk_context ctx;
+ struct XSurface *surf;
+ Cursor cursor;
+ Display *dpy;
+ Window root;
+} xlib;
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+static unsigned long
+nk_color_from_byte(const nk_byte *c)
+{
+ unsigned long res = 0;
+ res |= (unsigned long)c[0] << 16;
+ res |= (unsigned long)c[1] << 8;
+ res |= (unsigned long)c[2] << 0;
+ return (res);
+}
+
+static XSurface*
+nk_xsurf_create(int screen, unsigned int w, unsigned int h)
+{
+ XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));
+ surface->w = w;
+ surface->h = h;
+ surface->dpy = xlib.dpy;
+ surface->screen = screen;
+ surface->root = xlib.root;
+ surface->gc = XCreateGC(xlib.dpy, xlib.root, 0, NULL);
+ XSetLineAttributes(xlib.dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
+ surface->drawable = XCreatePixmap(xlib.dpy, xlib.root, w, h,
+ (unsigned int)DefaultDepth(xlib.dpy, screen));
+ return surface;
+}
+
+static void
+nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)
+{
+ if(!surf) return;
+ if (surf->w == w && surf->h == h) return;
+ surf->w = w; surf->h = h;
+ if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);
+ surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,
+ (unsigned int)DefaultDepth(surf->dpy, surf->screen));
+}
+
+static void
+nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)
+{
+ XRectangle clip_rect;
+ clip_rect.x = (short)(x-1);
+ clip_rect.y = (short)(y-1);
+ clip_rect.width = (unsigned short)(w+2);
+ clip_rect.height = (unsigned short)(h+2);
+ XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
+}
+
+static void
+nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,
+ short y1, unsigned int line_thickness, struct nk_color col)
+{
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
+{
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ if (r == 0) {
+ XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
+ } else {
+ short xc = x + r;
+ short yc = y + r;
+ short wc = (short)(w - 2 * r);
+ short hc = (short)(h - 2 * r);
+
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc);
+
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+ (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y,
+ (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+ (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+ (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
+ }
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w,
+ unsigned short h, unsigned short r, struct nk_color col)
+{
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ if (r == 0) {
+ XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
+ } else {
+ short xc = x + r;
+ short yc = y + r;
+ short wc = (short)(w - 2 * r);
+ short hc = (short)(h - 2 * r);
+
+ XPoint pnts[12];
+ pnts[0].x = x;
+ pnts[0].y = yc;
+ pnts[1].x = xc;
+ pnts[1].y = yc;
+ pnts[2].x = xc;
+ pnts[2].y = y;
+
+ pnts[3].x = xc + wc;
+ pnts[3].y = y;
+ pnts[4].x = xc + wc;
+ pnts[4].y = yc;
+ pnts[5].x = x + w;
+ pnts[5].y = yc;
+
+ pnts[6].x = x + w;
+ pnts[6].y = yc + hc;
+ pnts[7].x = xc + wc;
+ pnts[7].y = yc + hc;
+ pnts[8].x = xc + wc;
+ pnts[8].y = y + h;
+
+ pnts[9].x = xc;
+ pnts[9].y = y + h;
+ pnts[10].x = xc;
+ pnts[10].y = yc + hc;
+ pnts[11].x = x;
+ pnts[11].y = yc + hc;
+
+ XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
+ XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+ (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+ XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
+ (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+ XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+ (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+ XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+ (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
+ }
+}
+
+static void
+nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,
+ short y1, short x2, short y2, struct nk_color col)
+{
+ XPoint pnts[3];
+ unsigned long c = nk_color_from_byte(&col.r);
+ pnts[0].x = (short)x0;
+ pnts[0].y = (short)y0;
+ pnts[1].x = (short)x1;
+ pnts[1].y = (short)y1;
+ pnts[2].x = (short)x2;
+ pnts[2].y = (short)y2;
+ XSetForeground(surf->dpy, surf->gc, c);
+ XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
+}
+
+static void
+nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
+ short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
+{
+ XPoint pnts[3];
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
+ struct nk_color col)
+{
+ int i = 0;
+ #define MAX_POINTS 64
+ XPoint xpnts[MAX_POINTS];
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ for (i = 0; i < count && i < MAX_POINTS; ++i) {
+ xpnts[i].x = pnts[i].x;
+ xpnts[i].y = pnts[i].y;
+ }
+ XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);
+ #undef MAX_POINTS
+}
+
+static void
+nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
+ unsigned short line_thickness, struct nk_color col)
+{
+ int i = 0;
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ for (i = 1; i < count; ++i)
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,
+ int count, unsigned short line_thickness, struct nk_color col)
+{
+ int i = 0;
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ XSetForeground(surf->dpy, surf->gc, c);
+ for (i = 0; i < count-1; ++i)
+ XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,
+ unsigned short h, struct nk_color col)
+{
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
+ (unsigned)w, (unsigned)h, 0, 360 * 64);
+}
+
+static void
+nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
+ unsigned short h, unsigned short line_thickness, struct nk_color col)
+{
+ unsigned long c = nk_color_from_byte(&col.r);
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ XSetForeground(surf->dpy, surf->gc, c);
+ XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
+ (unsigned)w, (unsigned)h, 0, 360 * 64);
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
+ struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
+ unsigned int num_segments, unsigned short line_thickness, struct nk_color col)
+{
+ unsigned int i_step;
+ float t_step;
+ struct nk_vec2i last = p1;
+
+ XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
+ num_segments = MAX(num_segments, 1);
+ t_step = 1.0f/(float)num_segments;
+ for (i_step = 1; i_step <= num_segments; ++i_step) {
+ float t = t_step * (float)i_step;
+ float u = 1.0f - t;
+ float w1 = u*u*u;
+ float w2 = 3*u*u*t;
+ float w3 = 3*u*t*t;
+ float w4 = t * t *t;
+ float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
+ float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
+ nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);
+ last.x = (short)x; last.y = (short)y;
+ }
+ XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
+}
+
+static void
+nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
+ const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg)
+{
+ int tx, ty;
+ unsigned long bg = nk_color_from_byte(&cbg.r);
+ unsigned long fg = nk_color_from_byte(&cfg.r);
+
+ XSetForeground(surf->dpy, surf->gc, bg);
+ XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
+ if(!text || !font || !len) return;
+
+ tx = (int)x;
+ ty = (int)y + font->ascent;
+ XSetForeground(surf->dpy, surf->gc, fg);
+ if(font->set)
+ XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
+ else
+ XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
+}
+
+static void
+nk_xsurf_clear(XSurface *surf, unsigned long color)
+{
+ XSetForeground(surf->dpy, surf->gc, color);
+ XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
+}
+
+static void
+nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h)
+{
+ XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0);
+}
+
+static void
+nk_xsurf_del(XSurface *surf)
+{
+ XFreePixmap(surf->dpy, surf->drawable);
+ XFreeGC(surf->dpy, surf->gc);
+ free(surf);
+}
+
+XFont*
+nk_xfont_create(Display *dpy, const char *name)
+{
+ int n;
+ char *def, **missing;
+ XFont *font = (XFont*)calloc(1, sizeof(XFont));
+ font->set = XCreateFontSet(dpy, name, &missing, &n, &def);
+ if(missing) {
+ while(n--)
+ fprintf(stderr, "missing fontset: %s\n", missing[n]);
+ XFreeStringList(missing);
+ }
+
+ if(font->set) {
+ XFontStruct **xfonts;
+ char **font_names;
+ XExtentsOfFontSet(font->set);
+ n = XFontsOfFontSet(font->set, &xfonts, &font_names);
+ while(n--) {
+ font->ascent = MAX(font->ascent, (*xfonts)->ascent);
+ font->descent = MAX(font->descent,(*xfonts)->descent);
+ xfonts++;
+ }
+ } else {
+ if(!(font->xfont = XLoadQueryFont(dpy, name))
+ && !(font->xfont = XLoadQueryFont(dpy, "fixed"))) {
+ free(font);
+ return 0;
+ }
+ font->ascent = font->xfont->ascent;
+ font->descent = font->xfont->descent;
+ }
+ font->height = font->ascent + font->descent;
+ return font;
+}
+
+static float
+nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+ XFont *font = (XFont*)handle.ptr;
+ XRectangle r;
+ if(!font || !text)
+ return 0;
+
+ if(font->set) {
+ XmbTextExtents(font->set, (const char*)text, len, NULL, &r);
+ return (float)r.width;
+ } else{
+ int w = XTextWidth(font->xfont, (const char*)text, len);
+ return (float)w;
+ }
+}
+
+void
+nk_xfont_del(Display *dpy, XFont *font)
+{
+ if(!font) return;
+ if(font->set)
+ XFreeFontSet(dpy, font->set);
+ else
+ XFreeFont(dpy, font->xfont);
+ free(font);
+}
+
+NK_API struct nk_context*
+nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root,
+ unsigned int w, unsigned int h)
+{
+ struct nk_user_font *font = &xfont->handle;
+ font->userdata = nk_handle_ptr(xfont);
+ font->height = (float)xfont->height;
+ font->width = nk_xfont_get_text_width;
+ xlib.dpy = dpy;
+ xlib.root = root;
+
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1);
+ if (blank == None) return 0;
+ xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ xlib.surf = nk_xsurf_create(screen, w, h);
+ nk_init_default(&xlib.ctx, font);
+ return &xlib.ctx;
+}
+
+NK_API void
+nk_xlib_set_font(XFont *xfont)
+{
+ struct nk_user_font *font = &xfont->handle;
+ font->userdata = nk_handle_ptr(xfont);
+ font->height = (float)xfont->height;
+ font->width = nk_xfont_get_text_width;
+ nk_style_set_font(&xlib.ctx, font);
+}
+
+NK_API int
+nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
+{
+ struct nk_context *ctx = &xlib.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(xlib.dpy, xlib.root, xlib.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0,
+ (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);
+ XUndefineCursor(xlib.dpy, xlib.root);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ if (evt->type == KeyPress || evt->type == KeyRelease)
+ {
+ /* Key handler */
+ int ret, down = (evt->type == KeyPress);
+ KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
+ if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down);
+ else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down);
+ else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_Escape) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else {
+ if (*code == 'c' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_COPY, down);
+ else if (*code == 'v' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_PASTE, down);
+ else if (*code == 'x' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_CUT, down);
+ else if (*code == 'z' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
+ else if (*code == 'r' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
+ else if (*code == XK_Left && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else if (*code == XK_Right && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else if (*code == 'b' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
+ else if (*code == 'e' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
+ else {
+ if (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
+ /* Button handler */
+ int down = (evt->type == ButtonPress);
+ const int x = evt->xbutton.x, y = evt->xbutton.y;
+ if (evt->xbutton.button == Button1)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if (evt->xbutton.button == Button2)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else if (evt->xbutton.button == Button3)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else if (evt->xbutton.button == Button4)
+ nk_input_scroll(ctx, 1.0f);
+ else if (evt->xbutton.button == Button5)
+ nk_input_scroll(ctx, -1.0f);
+ else return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(xlib.dpy, None, xlib.surf->root, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } else if (evt->type == Expose || evt->type == ConfigureNotify) {
+ /* Window resize handler */
+ unsigned int width, height;
+ XWindowAttributes attr;
+ XGetWindowAttributes(dpy, win, &attr);
+ width = (unsigned int)attr.width;
+ height = (unsigned int)attr.height;
+ nk_xsurf_resize(xlib.surf, width, height);
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API void
+nk_xlib_shutdown(void)
+{
+ nk_xsurf_del(xlib.surf);
+ nk_free(&xlib.ctx);
+ XFreeCursor(xlib.dpy, xlib.cursor);
+ nk_memset(&xlib, 0, sizeof(xlib));
+}
+
+NK_API void
+nk_xlib_render(Drawable screen, struct nk_color clear)
+{
+ const struct nk_command *cmd;
+ struct nk_context *ctx = &xlib.ctx;
+ XSurface *surf = xlib.surf;
+
+ nk_xsurf_clear(xlib.surf, nk_color_from_byte(&clear.r));
+ nk_foreach(cmd, &xlib.ctx)
+ {
+ switch (cmd->type) {
+ case NK_COMMAND_NOP: break;
+ case NK_COMMAND_SCISSOR: {
+ const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
+ nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h);
+ } break;
+ case NK_COMMAND_LINE: {
+ const struct nk_command_line *l = (const struct nk_command_line *)cmd;
+ nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x,
+ l->end.y, l->line_thickness, l->color);
+ } break;
+ case NK_COMMAND_RECT: {
+ const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
+ nk_xsurf_stroke_rect(surf, r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->line_thickness, r->color);
+ } break;
+ case NK_COMMAND_RECT_FILLED: {
+ const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
+ nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h,
+ (unsigned short)r->rounding, r->color);
+ } break;
+ case NK_COMMAND_CIRCLE: {
+ const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
+ nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
+ } break;
+ case NK_COMMAND_CIRCLE_FILLED: {
+ const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
+ nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color);
+ } break;
+ case NK_COMMAND_TRIANGLE: {
+ const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
+ nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->line_thickness, t->color);
+ } break;
+ case NK_COMMAND_TRIANGLE_FILLED: {
+ const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
+ nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
+ t->c.x, t->c.y, t->color);
+ } break;
+ case NK_COMMAND_POLYGON: {
+ const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
+ nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color);
+ } break;
+ case NK_COMMAND_POLYGON_FILLED: {
+ const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
+ nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color);
+ } break;
+ case NK_COMMAND_POLYLINE: {
+ const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
+ nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color);
+ } break;
+ case NK_COMMAND_TEXT: {
+ const struct nk_command_text *t = (const struct nk_command_text*)cmd;
+ nk_xsurf_draw_text(surf, t->x, t->y, t->w, t->h,
+ (const char*)t->string, t->length,
+ (XFont*)t->font->userdata.ptr,
+ t->background, t->foreground);
+ } break;
+ case NK_COMMAND_CURVE: {
+ const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
+ nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1],
+ q->end, 22, q->line_thickness, q->color);
+ } break;
+ case NK_COMMAND_RECT_MULTI_COLOR:
+ case NK_COMMAND_IMAGE:
+ case NK_COMMAND_ARC:
+ case NK_COMMAND_ARC_FILLED:
+ default: break;
+ }
+ }
+ nk_clear(ctx);
+ nk_xsurf_blit(screen, surf, surf->w, surf->h);
+}
+#endif
diff --git a/nuklear/demo/x11_opengl2/Makefile b/nuklear/demo/x11_opengl2/Makefile
new file mode 100644
index 0000000..1173b6c
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/Makefile
@@ -0,0 +1,26 @@
+# Install
+BIN = demo
+
+# Compiler
+CC = clang
+DCC = gcc
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+# Modes
+.PHONY: gcc
+gcc: CC = gcc
+gcc: $(BIN)
+
+.PHONY: clang
+clang: CC = clang
+clang: $(BIN)
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU
diff --git a/nuklear/demo/x11_opengl2/main.c b/nuklear/demo/x11_opengl2/main.c
new file mode 100644
index 0000000..cfe5604
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/main.c
@@ -0,0 +1,320 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glx.h>
+#include <GL/glxext.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_XLIB_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_xlib_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+struct XWindow {
+ Display *dpy;
+ Window win;
+ XVisualInfo *vis;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XWindowAttributes attr;
+ GLXFBConfig fbc;
+ int width, height;
+};
+static int gl_err = FALSE;
+static int gl_error_handler(Display *dpy, XErrorEvent *ev)
+{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static int
+has_extension(const char *string, const char *ext)
+{
+ const char *start, *where, *term;
+ where = strchr(ext, ' ');
+ if (where || *ext == '\0')
+ return FALSE;
+
+ for (start = string;;) {
+ where = strstr((const char*)start, ext);
+ if (!where) break;
+ term = where + strlen(ext);
+ if (where == start || *(where - 1) == ' ') {
+ if (*term == ' ' || *term == '\0')
+ return TRUE;
+ }
+ start = term;
+ }
+ return FALSE;
+}
+
+int main(int argc, char **argv)
+{
+ /* Platform */
+ int running = 1;
+ struct XWindow win;
+ GLXContext glContext;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ memset(&win, 0, sizeof(win));
+ win.dpy = XOpenDisplay(NULL);
+ if (!win.dpy) die("Failed to open X display\n");
+ {
+ /* check glx version */
+ int glx_major, glx_minor;
+ if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))
+ die("[X11]: Error: Failed to query OpenGL version\n");
+ if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))
+ die("[X11]: Error: Invalid GLX version!\n");
+ }
+ {
+ /* find and pick matching framebuffer visual */
+ int fb_count;
+ static GLint attr[] = {
+ GLX_X_RENDERABLE, True,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 24,
+ GLX_STENCIL_SIZE, 8,
+ GLX_DOUBLEBUFFER, True,
+ None
+ };
+ GLXFBConfig *fbc;
+ fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
+ if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
+ {
+ /* pick framebuffer with most samples per pixel */
+ int i;
+ int fb_best = -1, best_num_samples = -1;
+ for (i = 0; i < fb_count; ++i) {
+ XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);
+ if (vi) {
+ int sample_buffer, samples;
+ glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);
+ glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);
+ if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))
+ fb_best = i; best_num_samples = samples;
+ }
+ }
+ win.fbc = fbc[fb_best];
+ XFree(fbc);
+ win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);
+ }
+ }
+ {
+ /* create window */
+ win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);
+ win.swa.colormap = win.cmap;
+ win.swa.background_pixmap = None;
+ win.swa.border_pixel = 0;
+ win.swa.event_mask =
+ ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPress | ButtonReleaseMask| ButtonMotionMask |
+ Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
+ PointerMotionMask| StructureNotifyMask;
+ win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,
+ WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,
+ win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);
+ if (!win.win) die("[X11]: Failed to create window\n");
+ XFree(win.vis);
+ XStoreName(win.dpy, win.win, "Demo");
+ XMapWindow(win.dpy, win.win);
+ }
+ {
+ /* create opengl context */
+ typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+ int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
+ const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
+ glxCreateContext create_context = (glxCreateContext)
+ glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
+
+ gl_err = FALSE;
+ if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
+ fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
+ fprintf(stdout, "[X11]: ... using old-style GLX context\n");
+ glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
+ } else {
+ GLint attr[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ None
+ };
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ XSync(win.dpy, False);
+ if (gl_err || !glContext) {
+ /* Could not create GL 3.0 context. Fallback to old 2.x context.
+ * If a version below 3.0 is requested, implementations will
+ * return the newest context version compatible with OpenGL
+ * version less than version 3.0.*/
+ attr[1] = 1; attr[3] = 0;
+ gl_err = FALSE;
+ fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
+ fprintf(stdout, "[X11] ... using old-style GLX context!\n");
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ }
+ }
+ XSync(win.dpy, False);
+ XSetErrorHandler(old_handler);
+ if (gl_err || !glContext)
+ die("[X11]: Failed to create an OpenGL context\n");
+ glXMakeCurrent(win.dpy, win.win, glContext);
+ }
+
+ ctx = nk_x11_init(win.dpy, win.win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+ {struct nk_font_atlas *atlas;
+ nk_x11_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_x11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ nk_input_begin(ctx);
+ while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)){
+ if (XFilterEvent(&evt, win.win)) continue;
+ nk_x11_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ XGetWindowAttributes(win.dpy, win.win, &win.attr);
+ glViewport(0, 0, win.width, win.height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glXSwapBuffers(win.dpy, win.win);}
+ }
+
+ nk_x11_shutdown();
+ glXMakeCurrent(win.dpy, 0, 0);
+ glXDestroyContext(win.dpy, glContext);
+ XUnmapWindow(win.dpy, win.win);
+ XFreeColormap(win.dpy, win.cmap);
+ XDestroyWindow(win.dpy, win.win);
+ XCloseDisplay(win.dpy);
+ return 0;
+
+}
diff --git a/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h b/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h
new file mode 100644
index 0000000..a814455
--- /dev/null
+++ b/nuklear/demo/x11_opengl2/nuklear_xlib_gl2.h
@@ -0,0 +1,357 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_GL3_H_
+#define NK_XLIB_GL3_H_
+
+#include <X11/Xlib.h>
+NK_API struct nk_context* nk_x11_init(Display *dpy, Window win);
+NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_x11_font_stash_end(void);
+NK_API int nk_x11_handle_event(XEvent *evt);
+NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_x11_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_GL2_IMPLEMENTATION
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#include <GL/gl.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+struct nk_x11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct nk_x11_device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint font_tex;
+};
+
+static struct nk_x11 {
+ struct nk_x11_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ Cursor cursor;
+ Display *dpy;
+ Window win;
+} x11;
+
+NK_INTERN void
+nk_x11_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_x11_device *dev = &x11.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ /* setup global state */
+ struct nk_x11_device *dev = &x11.ogl;
+ int width, height;
+
+ XWindowAttributes attr;
+ XGetWindowAttributes(x11.dpy, x11.win, &attr);
+ width = attr.width;
+ height = attr.height;
+
+ glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* setup viewport/project */
+ glViewport(0,0,(GLsizei)width,(GLsizei)height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+ {
+ GLsizei vs = sizeof(struct nk_x11_vertex);
+ size_t vp = offsetof(struct nk_x11_vertex, position);
+ size_t vt = offsetof(struct nk_x11_vertex, uv);
+ size_t vc = offsetof(struct nk_x11_vertex, col);
+
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ const nk_draw_index *offset = NULL;
+ struct nk_buffer vbuf, ebuf;
+
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_x11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* convert shapes into vertexes */
+ nk_buffer_init_default(&vbuf);
+ nk_buffer_init_default(&ebuf);
+ nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+ /* setup vertex buffer pointer */
+ {const void *vertices = nk_buffer_memory_const(&vbuf);
+ glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+ glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+ glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}
+
+ /* iterate over and execute each draw command */
+ offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+ nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
+ (GLint)(cmd->clip_rect.w),
+ (GLint)(cmd->clip_rect.h));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&x11.ctx);
+ nk_buffer_free(&vbuf);
+ nk_buffer_free(&ebuf);
+ }
+
+ /* default OpenGL state */
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glPopAttrib();
+
+}
+
+NK_API void
+nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&x11.atlas);
+ nk_font_atlas_begin(&x11.atlas);
+ *atlas = &x11.atlas;
+}
+
+NK_API void
+nk_x11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_x11_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
+ if (x11.atlas.default_font)
+ nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
+}
+
+NK_API int
+nk_x11_handle_event(XEvent *evt)
+{
+ struct nk_context *ctx = &x11.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(x11.dpy, x11.win, x11.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
+ (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ XUndefineCursor(x11.dpy, x11.win);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ if (evt->type == KeyPress || evt->type == KeyRelease)
+ {
+ /* Key handler */
+ int ret, down = (evt->type == KeyPress);
+ KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
+ if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down);
+ else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down);
+ else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else {
+ if (*code == 'c' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_COPY, down);
+ else if (*code == 'v' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_PASTE, down);
+ else if (*code == 'x' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_CUT, down);
+ else if (*code == 'z' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
+ else if (*code == 'r' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
+ else if (*code == XK_Left && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else if (*code == XK_Right && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else if (*code == 'b' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
+ else if (*code == 'e' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
+ else {
+ if (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
+ /* Button handler */
+ int down = (evt->type == ButtonPress);
+ const int x = evt->xbutton.x, y = evt->xbutton.y;
+ if (evt->xbutton.button == Button1)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if (evt->xbutton.button == Button2)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else if (evt->xbutton.button == Button3)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else if (evt->xbutton.button == Button4)
+ nk_input_scroll(ctx, 1.0f);
+ else if (evt->xbutton.button == Button5)
+ nk_input_scroll(ctx, -1.0f);
+ else return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API struct nk_context*
+nk_x11_init(Display *dpy, Window win)
+{
+ x11.dpy = dpy;
+ x11.win = win;
+
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
+ if (blank == None) return 0;
+ x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ nk_buffer_init_default(&x11.ogl.cmds);
+ nk_init_default(&x11.ctx, 0);
+ return &x11.ctx;
+}
+
+NK_API void
+nk_x11_shutdown(void)
+{
+ struct nk_x11_device *dev = &x11.ogl;
+ nk_font_atlas_clear(&x11.atlas);
+ nk_free(&x11.ctx);
+ glDeleteTextures(1, &dev->font_tex);
+ nk_buffer_free(&dev->cmds);
+ XFreeCursor(x11.dpy, x11.cursor);
+ memset(&x11, 0, sizeof(x11));
+}
+
+#endif
diff --git a/nuklear/demo/x11_opengl3/Makefile b/nuklear/demo/x11_opengl3/Makefile
new file mode 100644
index 0000000..1173b6c
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/Makefile
@@ -0,0 +1,26 @@
+# Install
+BIN = demo
+
+# Compiler
+CC = clang
+DCC = gcc
+
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+
+SRC = main.c
+OBJ = $(SRC:.c=.o)
+
+# Modes
+.PHONY: gcc
+gcc: CC = gcc
+gcc: $(BIN)
+
+.PHONY: clang
+clang: CC = clang
+clang: $(BIN)
+
+$(BIN):
+ @mkdir -p bin
+ rm -f bin/$(BIN) $(OBJS)
+ $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU
diff --git a/nuklear/demo/x11_opengl3/main.c b/nuklear/demo/x11_opengl3/main.c
new file mode 100644
index 0000000..cd026f9
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/main.c
@@ -0,0 +1,317 @@
+/* nuklear - v1.17 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_XLIB_GL3_IMPLEMENTATION
+#define NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include "../../nuklear.h"
+#include "nuklear_xlib_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ * EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+struct XWindow {
+ Display *dpy;
+ Window win;
+ XVisualInfo *vis;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XWindowAttributes attr;
+ GLXFBConfig fbc;
+ int width, height;
+};
+static int gl_err = FALSE;
+static int gl_error_handler(Display *dpy, XErrorEvent *ev)
+{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static int
+has_extension(const char *string, const char *ext)
+{
+ const char *start, *where, *term;
+ where = strchr(ext, ' ');
+ if (where || *ext == '\0')
+ return FALSE;
+
+ for (start = string;;) {
+ where = strstr((const char*)start, ext);
+ if (!where) break;
+ term = where + strlen(ext);
+ if (where == start || *(where - 1) == ' ') {
+ if (*term == ' ' || *term == '\0')
+ return TRUE;
+ }
+ start = term;
+ }
+ return FALSE;
+}
+
+int main(int argc, char **argv)
+{
+ /* Platform */
+ int running = 1;
+ struct XWindow win;
+ GLXContext glContext;
+ struct nk_context *ctx;
+ struct nk_color background;
+
+ memset(&win, 0, sizeof(win));
+ win.dpy = XOpenDisplay(NULL);
+ if (!win.dpy) die("Failed to open X display\n");
+ {
+ /* check glx version */
+ int glx_major, glx_minor;
+ if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))
+ die("[X11]: Error: Failed to query OpenGL version\n");
+ if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))
+ die("[X11]: Error: Invalid GLX version!\n");
+ }
+ {
+ /* find and pick matching framebuffer visual */
+ int fb_count;
+ static GLint attr[] = {
+ GLX_X_RENDERABLE, True,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 24,
+ GLX_STENCIL_SIZE, 8,
+ GLX_DOUBLEBUFFER, True,
+ None
+ };
+ GLXFBConfig *fbc;
+ fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
+ if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
+ {
+ /* pick framebuffer with most samples per pixel */
+ int i;
+ int fb_best = -1, best_num_samples = -1;
+ for (i = 0; i < fb_count; ++i) {
+ XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);
+ if (vi) {
+ int sample_buffer, samples;
+ glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);
+ glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);
+ if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))
+ fb_best = i; best_num_samples = samples;
+ }
+ }
+ win.fbc = fbc[fb_best];
+ XFree(fbc);
+ win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);
+ }
+ }
+ {
+ /* create window */
+ win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);
+ win.swa.colormap = win.cmap;
+ win.swa.background_pixmap = None;
+ win.swa.border_pixel = 0;
+ win.swa.event_mask =
+ ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPress | ButtonReleaseMask| ButtonMotionMask |
+ Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
+ PointerMotionMask| StructureNotifyMask;
+ win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,
+ WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,
+ win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);
+ if (!win.win) die("[X11]: Failed to create window\n");
+ XFree(win.vis);
+ XStoreName(win.dpy, win.win, "Demo");
+ XMapWindow(win.dpy, win.win);
+ }
+ {
+ /* create opengl context */
+ typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+ int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
+ const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
+ glxCreateContext create_context = (glxCreateContext)
+ glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
+
+ gl_err = FALSE;
+ if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
+ fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
+ fprintf(stdout, "[X11]: ... using old-style GLX context\n");
+ glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
+ } else {
+ GLint attr[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ None
+ };
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ XSync(win.dpy, False);
+ if (gl_err || !glContext) {
+ /* Could not create GL 3.0 context. Fallback to old 2.x context.
+ * If a version below 3.0 is requested, implementations will
+ * return the newest context version compatible with OpenGL
+ * version less than version 3.0.*/
+ attr[1] = 1; attr[3] = 0;
+ gl_err = FALSE;
+ fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
+ fprintf(stdout, "[X11] ... using old-style GLX context!\n");
+ glContext = create_context(win.dpy, win.fbc, 0, True, attr);
+ }
+ }
+ XSync(win.dpy, False);
+ XSetErrorHandler(old_handler);
+ if (gl_err || !glContext)
+ die("[X11]: Failed to create an OpenGL context\n");
+ glXMakeCurrent(win.dpy, win.win, glContext);
+ }
+
+ ctx = nk_x11_init(win.dpy, win.win);
+ /* Load Fonts: if none of these are loaded a default font will be used */
+ {struct nk_font_atlas *atlas;
+ nk_x11_font_stash_begin(&atlas);
+ /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+ /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+ /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+ /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+ /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+ /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+ nk_x11_font_stash_end();
+ /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+ /*nk_style_set_font(ctx, &droid->handle);*/}
+
+ /* style.c */
+ /*set_style(ctx, THEME_WHITE);*/
+ /*set_style(ctx, THEME_RED);*/
+ /*set_style(ctx, THEME_BLUE);*/
+ /*set_style(ctx, THEME_DARK);*/
+
+ background = nk_rgb(28,48,62);
+ while (running)
+ {
+ /* Input */
+ XEvent evt;
+ nk_input_begin(ctx);
+ while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)){
+ if (XFilterEvent(&evt, win.win)) continue;
+ nk_x11_handle_event(&evt);
+ }
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+ NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+ {
+ enum {EASY, HARD};
+ static int op = EASY;
+ static int property = 20;
+
+ nk_layout_row_static(ctx, 30, 80, 1);
+ if (nk_button_label(ctx, "button"))
+ fprintf(stdout, "button pressed\n");
+ nk_layout_row_dynamic(ctx, 30, 2);
+ if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+ if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, "background:", NK_TEXT_LEFT);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+ nk_layout_row_dynamic(ctx, 120, 1);
+ background = nk_color_picker(ctx, background, NK_RGBA);
+ nk_layout_row_dynamic(ctx, 25, 1);
+ background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+ background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+ background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+ background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ if (nk_window_is_closed(ctx, "Demo")) break;
+
+ /* -------------- EXAMPLES ---------------- */
+ /*calculator(ctx);*/
+ /*overview(ctx);*/
+ /*node_editor(ctx);*/
+ /* ----------------------------------------- */
+
+ /* Draw */
+ {float bg[4];
+ nk_color_fv(bg, background);
+ XGetWindowAttributes(win.dpy, win.win, &win.attr);
+ glViewport(0, 0, win.width, win.height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(bg[0], bg[1], bg[2], bg[3]);
+ /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state
+ * with blending, scissor, face culling, depth test and viewport and
+ * defaults everything back into a default state.
+ * Make sure to either a.) save and restore or b.) reset your own state after
+ * rendering the UI. */
+ nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+ glXSwapBuffers(win.dpy, win.win);}
+ }
+
+ nk_x11_shutdown();
+ glXMakeCurrent(win.dpy, 0, 0);
+ glXDestroyContext(win.dpy, glContext);
+ XUnmapWindow(win.dpy, win.win);
+ XFreeColormap(win.dpy, win.cmap);
+ XDestroyWindow(win.dpy, win.win);
+ XCloseDisplay(win.dpy);
+ return 0;
+
+}
diff --git a/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h b/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h
new file mode 100644
index 0000000..b0f56b9
--- /dev/null
+++ b/nuklear/demo/x11_opengl3/nuklear_xlib_gl3.h
@@ -0,0 +1,725 @@
+/*
+ * Nuklear - v1.17 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ * API
+ *
+ * ===============================================================
+ */
+#ifndef NK_XLIB_GL3_H_
+#define NK_XLIB_GL3_H_
+
+#include <X11/Xlib.h>
+NK_API struct nk_context* nk_x11_init(Display *dpy, Window win);
+NK_API void nk_x11_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_x11_font_stash_end(void);
+NK_API int nk_x11_handle_event(XEvent *evt);
+NK_API void nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void nk_x11_shutdown(void);
+NK_API int nk_x11_device_create(void);
+NK_API void nk_x11_device_destroy(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ * IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_XLIB_GL3_IMPLEMENTATION
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include <GL/glxext.h>
+
+/* GL_ARB_vertex_buffer_object */
+typedef void(*nkglGenBuffers)(GLsizei, GLuint*);
+typedef void(*nkglBindBuffer)(GLenum, GLuint);
+typedef void(*nkglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
+typedef void(*nkglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);
+typedef void*(*nkglMapBuffer)(GLenum, GLenum);
+typedef GLboolean(*nkglUnmapBuffer)(GLenum);
+typedef void(*nkglDeleteBuffers)(GLsizei, GLuint*);
+/* GL_ARB_vertex_array_object */
+typedef void (*nkglGenVertexArrays)(GLsizei, GLuint*);
+typedef void (*nkglBindVertexArray)(GLuint);
+typedef void (*nkglDeleteVertexArrays)(GLsizei, const GLuint*);
+/* GL_ARB_vertex_program / GL_ARB_fragment_program */
+typedef void(*nkglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
+typedef void(*nkglEnableVertexAttribArray)(GLuint);
+typedef void(*nkglDisableVertexAttribArray)(GLuint);
+/* GL_ARB_framebuffer_object */
+typedef void(*nkglGenerateMipmap)(GLenum target);
+/* GLSL/OpenGL 2.0 core */
+typedef GLuint(*nkglCreateShader)(GLenum);
+typedef void(*nkglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);
+typedef void(*nkglCompileShader)(GLuint);
+typedef void(*nkglGetShaderiv)(GLuint, GLenum, GLint*);
+typedef void(*nkglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
+typedef void(*nkglDeleteShader)(GLuint);
+typedef GLuint(*nkglCreateProgram)(void);
+typedef void(*nkglAttachShader)(GLuint, GLuint);
+typedef void(*nkglDetachShader)(GLuint, GLuint);
+typedef void(*nkglLinkProgram)(GLuint);
+typedef void(*nkglUseProgram)(GLuint);
+typedef void(*nkglGetProgramiv)(GLuint, GLenum, GLint*);
+typedef void(*nkglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
+typedef void(*nkglDeleteProgram)(GLuint);
+typedef GLint(*nkglGetUniformLocation)(GLuint, const GLchar*);
+typedef GLint(*nkglGetAttribLocation)(GLuint, const GLchar*);
+typedef void(*nkglUniform1i)(GLint, GLint);
+typedef void(*nkglUniform1f)(GLint, GLfloat);
+typedef void(*nkglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void(*nkglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);
+
+static nkglGenBuffers glGenBuffers;
+static nkglBindBuffer glBindBuffer;
+static nkglBufferData glBufferData;
+static nkglBufferSubData glBufferSubData;
+static nkglMapBuffer glMapBuffer;
+static nkglUnmapBuffer glUnmapBuffer;
+static nkglDeleteBuffers glDeleteBuffers;
+static nkglGenVertexArrays glGenVertexArrays;
+static nkglBindVertexArray glBindVertexArray;
+static nkglDeleteVertexArrays glDeleteVertexArrays;
+static nkglVertexAttribPointer glVertexAttribPointer;
+static nkglEnableVertexAttribArray glEnableVertexAttribArray;
+static nkglDisableVertexAttribArray glDisableVertexAttribArray;
+static nkglGenerateMipmap glGenerateMipmap;
+static nkglCreateShader glCreateShader;
+static nkglShaderSource glShaderSource;
+static nkglCompileShader glCompileShader;
+static nkglGetShaderiv glGetShaderiv;
+static nkglGetShaderInfoLog glGetShaderInfoLog;
+static nkglDeleteShader glDeleteShader;
+static nkglCreateProgram glCreateProgram;
+static nkglAttachShader glAttachShader;
+static nkglDetachShader glDetachShader;
+static nkglLinkProgram glLinkProgram;
+static nkglUseProgram glUseProgram;
+static nkglGetProgramiv glGetProgramiv;
+static nkglGetProgramInfoLog glGetProgramInfoLog;
+static nkglDeleteProgram glDeleteProgram;
+static nkglGetUniformLocation glGetUniformLocation;
+static nkglGetAttribLocation glGetAttribLocation;
+static nkglUniform1i glUniform1i;
+static nkglUniform1f glUniform1f;
+static nkglUniformMatrix3fv glUniformMatrix3fv;
+static nkglUniformMatrix4fv glUniformMatrix4fv;
+
+enum graphics_card_vendors {
+ VENDOR_UNKNOWN,
+ VENDOR_NVIDIA,
+ VENDOR_AMD,
+ VENDOR_INTEL
+};
+
+struct opengl_info {
+ /* info */
+ const char *vendor_str;
+ const char *version_str;
+ const char *extensions_str;
+ const char *renderer_str;
+ const char *glsl_version_str;
+ enum graphics_card_vendors vendor;
+ /* version */
+ float version;
+ int major_version;
+ int minor_version;
+ /* extensions */
+ int glsl_available;
+ int vertex_buffer_obj_available;
+ int vertex_array_obj_available;
+ int map_buffer_range_available;
+ int fragment_program_available;
+ int frame_buffer_object_available;
+};
+#endif
+
+struct nk_x11_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct nk_x11_device {
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+ struct opengl_info info;
+#endif
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+static struct nk_x11 {
+ struct nk_x11_device ogl;
+ struct nk_context ctx;
+ struct nk_font_atlas atlas;
+ Cursor cursor;
+ Display *dpy;
+ Window win;
+} x11;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+#include <GL/glx.h>
+
+NK_INTERN int
+nk_x11_stricmpn(const char *a, const char *b, int len)
+{
+ int i = 0;
+ for (i = 0; i < len && a[i] && b[i]; ++i)
+ if (a[i] != b[i]) return 1;
+ if (i != len) return 1;
+ return 0;
+}
+
+NK_INTERN int
+nk_x11_check_extension(struct opengl_info *GL, const char *ext)
+{
+ const char *start, *where, *term;
+ where = strchr(ext, ' ');
+ if (where || *ext == '\0')
+ return FALSE;
+
+ for (start = GL->extensions_str;;) {
+ where = strstr((const char*)start, ext);
+ if (!where) break;
+ term = where + strlen(ext);
+ if (where == start || *(where - 1) == ' ') {
+ if (*term == ' ' || *term == '\0')
+ return TRUE;
+ }
+ start = term;
+ }
+ return FALSE;
+}
+
+#define GL_EXT(name) (nk##name)nk_gl_ext(#name)
+NK_INTERN __GLXextFuncPtr
+nk_gl_ext(const char *name)
+{
+ __GLXextFuncPtr func;
+ func = glXGetProcAddress((const GLubyte*)name);
+ if (!func) {
+ fprintf(stdout, "[GL]: failed to load extension: %s", name);
+ return NULL;
+ }
+ return func;
+}
+
+NK_INTERN int
+nk_load_opengl(struct opengl_info *gl)
+{
+ int failed = FALSE;
+ gl->version_str = (const char*)glGetString(GL_VERSION);
+ glGetIntegerv(GL_MAJOR_VERSION, &gl->major_version);
+ glGetIntegerv(GL_MINOR_VERSION, &gl->minor_version);
+ if (gl->major_version < 2) {
+ fprintf(stderr, "[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n");
+ return 0;
+ }
+
+ gl->version = (float)gl->major_version + (float)gl->minor_version * 0.1f;
+ gl->renderer_str = (const char*)glGetString(GL_RENDERER);
+ gl->extensions_str = (const char*)glGetString(GL_EXTENSIONS);
+ gl->glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
+ gl->vendor_str = (const char*)glGetString(GL_VENDOR);
+ if (!nk_x11_stricmpn(gl->vendor_str, "ATI", 4) ||
+ !nk_x11_stricmpn(gl->vendor_str, "AMD", 4))
+ gl->vendor = VENDOR_AMD;
+ else if (!nk_x11_stricmpn(gl->vendor_str, "NVIDIA", 6))
+ gl->vendor = VENDOR_NVIDIA;
+ else if (!nk_x11_stricmpn(gl->vendor_str, "Intel", 5))
+ gl->vendor = VENDOR_INTEL;
+ else gl->vendor = VENDOR_UNKNOWN;
+
+ /* Extensions */
+ gl->glsl_available = (gl->version >= 2.0f);
+ if (gl->glsl_available) {
+ /* GLSL core in OpenGL > 2 */
+ glCreateShader = GL_EXT(glCreateShader);
+ glShaderSource = GL_EXT(glShaderSource);
+ glCompileShader = GL_EXT(glCompileShader);
+ glGetShaderiv = GL_EXT(glGetShaderiv);
+ glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog);
+ glDeleteShader = GL_EXT(glDeleteShader);
+ glCreateProgram = GL_EXT(glCreateProgram);
+ glAttachShader = GL_EXT(glAttachShader);
+ glDetachShader = GL_EXT(glDetachShader);
+ glLinkProgram = GL_EXT(glLinkProgram);
+ glUseProgram = GL_EXT(glUseProgram);
+ glGetProgramiv = GL_EXT(glGetProgramiv);
+ glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog);
+ glDeleteProgram = GL_EXT(glDeleteProgram);
+ glGetUniformLocation = GL_EXT(glGetUniformLocation);
+ glGetAttribLocation = GL_EXT(glGetAttribLocation);
+ glUniform1i = GL_EXT(glUniform1i);
+ glUniform1f = GL_EXT(glUniform1f);
+ glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv);
+ glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv);
+ }
+ gl->vertex_buffer_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_buffer_object");
+ if (gl->vertex_buffer_obj_available) {
+ /* GL_ARB_vertex_buffer_object */
+ glGenBuffers = GL_EXT(glGenBuffers);
+ glBindBuffer = GL_EXT(glBindBuffer);
+ glBufferData = GL_EXT(glBufferData);
+ glBufferSubData = GL_EXT(glBufferSubData);
+ glMapBuffer = GL_EXT(glMapBuffer);
+ glUnmapBuffer = GL_EXT(glUnmapBuffer);
+ glDeleteBuffers = GL_EXT(glDeleteBuffers);
+ }
+ gl->fragment_program_available = nk_x11_check_extension(gl, "GL_ARB_fragment_program");
+ if (gl->fragment_program_available) {
+ /* GL_ARB_vertex_program / GL_ARB_fragment_program */
+ glVertexAttribPointer = GL_EXT(glVertexAttribPointer);
+ glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray);
+ glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray);
+ }
+ gl->vertex_array_obj_available = nk_x11_check_extension(gl, "GL_ARB_vertex_array_object");
+ if (gl->vertex_array_obj_available) {
+ /* GL_ARB_vertex_array_object */
+ glGenVertexArrays = GL_EXT(glGenVertexArrays);
+ glBindVertexArray = GL_EXT(glBindVertexArray);
+ glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays);
+ }
+ gl->frame_buffer_object_available = nk_x11_check_extension(gl, "GL_ARB_framebuffer_object");
+ if (gl->frame_buffer_object_available) {
+ /* GL_ARB_framebuffer_object */
+ glGenerateMipmap = GL_EXT(glGenerateMipmap);
+ }
+ if (!gl->vertex_buffer_obj_available) {
+ fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n");
+ failed = TRUE;
+ }
+ if (!gl->fragment_program_available) {
+ fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n");
+ failed = TRUE;
+ }
+ if (!gl->vertex_array_obj_available) {
+ fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n");
+ failed = TRUE;
+ }
+ if (!gl->frame_buffer_object_available) {
+ fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n");
+ failed = TRUE;
+ }
+ return !failed;
+}
+#endif
+
+NK_API int
+nk_x11_device_create(void)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ struct nk_x11_device *dev = &x11.ogl;
+#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
+ if (!nk_load_opengl(&dev->info)) return 0;
+#endif
+ nk_buffer_init_default(&dev->cmds);
+
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_x11_vertex);
+ size_t vp = offsetof(struct nk_x11_vertex, position);
+ size_t vt = offsetof(struct nk_x11_vertex, uv);
+ size_t vc = offsetof(struct nk_x11_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ return 1;
+}
+
+NK_INTERN void
+nk_x11_device_upload_atlas(const void *image, int width, int height)
+{
+ struct nk_x11_device *dev = &x11.ogl;
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_x11_device_destroy(void)
+{
+ struct nk_x11_device *dev = &x11.ogl;
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+NK_API void
+nk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+ int width, height;
+ XWindowAttributes attr;
+ struct nk_x11_device *dev = &x11.ogl;
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ XGetWindowAttributes(x11.dpy, x11.win, &attr);
+ width = attr.width;
+ height = attr.height;
+
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ glViewport(0,0,(GLsizei)width,(GLsizei)height);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_x11_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
+ nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
+ nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
+ (GLint)(cmd->clip_rect.w),
+ (GLint)(cmd->clip_rect.h));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(&x11.ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+NK_API void
+nk_x11_font_stash_begin(struct nk_font_atlas **atlas)
+{
+ nk_font_atlas_init_default(&x11.atlas);
+ nk_font_atlas_begin(&x11.atlas);
+ *atlas = &x11.atlas;
+}
+
+NK_API void
+nk_x11_font_stash_end(void)
+{
+ const void *image; int w, h;
+ image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ nk_x11_device_upload_atlas(image, w, h);
+ nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.null);
+ if (x11.atlas.default_font)
+ nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);
+}
+
+NK_API int
+nk_x11_handle_event(XEvent *evt)
+{
+ struct nk_context *ctx = &x11.ctx;
+
+ /* optional grabbing behavior */
+ if (ctx->input.mouse.grab) {
+ XDefineCursor(x11.dpy, x11.win, x11.cursor);
+ ctx->input.mouse.grab = 0;
+ } else if (ctx->input.mouse.ungrab) {
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,
+ (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ XUndefineCursor(x11.dpy, x11.win);
+ ctx->input.mouse.ungrab = 0;
+ }
+
+ if (evt->type == KeyPress || evt->type == KeyRelease)
+ {
+ /* Key handler */
+ int ret, down = (evt->type == KeyPress);
+ KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
+ if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
+ else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down);
+ else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down);
+ else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down);
+ else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down);
+ else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down);
+ else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down);
+ else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down);
+ else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+ else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
+ else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
+ else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+ else if (*code == XK_Home) {
+ nk_input_key(ctx, NK_KEY_TEXT_START, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+ } else if (*code == XK_End) {
+ nk_input_key(ctx, NK_KEY_TEXT_END, down);
+ nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+ } else {
+ if (*code == 'c' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_COPY, down);
+ else if (*code == 'v' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_PASTE, down);
+ else if (*code == 'x' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_CUT, down);
+ else if (*code == 'z' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
+ else if (*code == 'r' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
+ else if (*code == XK_Left && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+ else if (*code == XK_Right && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+ else if (*code == 'b' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
+ else if (*code == 'e' && (evt->xkey.state & ControlMask))
+ nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
+ else {
+ if (*code == 'i')
+ nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);
+ else if (*code == 'r')
+ nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);
+ if (down) {
+ char buf[32];
+ KeySym keysym = 0;
+ if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
+ nk_input_glyph(ctx, buf);
+ }
+ }
+ }
+ XFree(code);
+ return 1;
+ } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
+ /* Button handler */
+ int down = (evt->type == ButtonPress);
+ const int x = evt->xbutton.x, y = evt->xbutton.y;
+ if (evt->xbutton.button == Button1)
+ nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+ if (evt->xbutton.button == Button2)
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+ else if (evt->xbutton.button == Button3)
+ nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+ else if (evt->xbutton.button == Button4)
+ nk_input_scroll(ctx, 1.0f);
+ else if (evt->xbutton.button == Button5)
+ nk_input_scroll(ctx, -1.0f);
+ else return 0;
+ return 1;
+ } else if (evt->type == MotionNotify) {
+ /* Mouse motion handler */
+ const int x = evt->xmotion.x, y = evt->xmotion.y;
+ nk_input_motion(ctx, x, y);
+ if (ctx->input.mouse.grabbed) {
+ ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
+ ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
+ XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);
+ }
+ return 1;
+ } else if (evt->type == KeymapNotify) {
+ XRefreshKeyboardMapping(&evt->xmapping);
+ return 1;
+ }
+ return 0;
+}
+
+NK_API struct nk_context*
+nk_x11_init(Display *dpy, Window win)
+{
+ if (!setlocale(LC_ALL,"")) return 0;
+ if (!XSupportsLocale()) return 0;
+ if (!XSetLocaleModifiers("@im=none")) return 0;
+ if (!nk_x11_device_create()) return 0;
+
+ x11.dpy = dpy;
+ x11.win = win;
+
+ /* create invisible cursor */
+ {static XColor dummy; char data[1] = {0};
+ Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);
+ if (blank == None) return 0;
+ x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
+ XFreePixmap(dpy, blank);}
+
+ nk_init_default(&x11.ctx, 0);
+ return &x11.ctx;
+}
+
+NK_API void
+nk_x11_shutdown(void)
+{
+ nk_font_atlas_clear(&x11.atlas);
+ nk_free(&x11.ctx);
+ nk_x11_device_destroy();
+ XFreeCursor(x11.dpy, x11.cursor);
+ memset(&x11, 0, sizeof(x11));
+}
+
+#endif
diff --git a/nuklear/example/Makefile b/nuklear/example/Makefile
new file mode 100644
index 0000000..22829a2
--- /dev/null
+++ b/nuklear/example/Makefile
@@ -0,0 +1,41 @@
+# Flags
+CFLAGS = -std=c99 -pedantic -O2
+LIBS :=
+
+ifeq ($(OS),Windows_NT)
+BIN := $(BIN).exe
+ LIBS := -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Darwin)
+ LIBS := -lglfw3 -framework OpenGL -lm -lGLEW -L/usr/local/lib
+ CFLAGS += -I/usr/local/include
+ else
+ LIBS := -lglfw -lGL -lm -lGLU -lGLEW
+ endif
+endif
+
+all: generate file_browser extended canvas skinning
+
+generate: clean
+ifeq ($(OS),Windows_NT)
+ @mkdir bin 2> nul || exit 0
+else
+ @mkdir -p bin
+endif
+
+clean:
+ @rm -rf bin
+
+file_browser: generate
+ $(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS)
+
+extended: generate
+ $(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS)
+
+canvas: generate
+ $(CC) $(CFLAGS) -o bin/canvas canvas.c $(LIBS)
+
+skinning: generate
+ $(CC) $(CFLAGS) -o bin/skinning skinning.c $(LIBS)
+
diff --git a/nuklear/example/canvas.c b/nuklear/example/canvas.c
new file mode 100644
index 0000000..c5f5634
--- /dev/null
+++ b/nuklear/example/canvas.c
@@ -0,0 +1,489 @@
+/* nuklear - v1.05 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_PRIVATE
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+#define NK_SHADER_VERSION "#version 150\n"
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static struct nk_image
+icon_load(const char *filename)
+{
+ int x,y,n;
+ GLuint tex;
+ unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+ if (!data) die("[SDL]: failed to load image: %s", filename);
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ return nk_image_id((int)tex);
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+ enum nk_anti_aliasing AA)
+{
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+ nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+ nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
+ (GLint)(cmd->clip_rect.w),
+ (GLint)(cmd->clip_rect.h));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+static void
+pump_input(struct nk_context *ctx, GLFWwindow *win)
+{
+ double x, y;
+ nk_input_begin(ctx);
+ glfwPollEvents();
+
+ nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+
+ if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+ glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
+ nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+ nk_input_key(ctx, NK_KEY_SHIFT, 1);
+ } else {
+ nk_input_key(ctx, NK_KEY_COPY, 0);
+ nk_input_key(ctx, NK_KEY_PASTE, 0);
+ nk_input_key(ctx, NK_KEY_CUT, 0);
+ nk_input_key(ctx, NK_KEY_SHIFT, 0);
+ }
+
+ glfwGetCursorPos(win, &x, &y);
+ nk_input_motion(ctx, (int)x, (int)y);
+ nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_end(ctx);
+}
+
+struct nk_canvas {
+ struct nk_command_buffer *painter;
+ struct nk_vec2 item_spacing;
+ struct nk_vec2 panel_padding;
+ struct nk_style_item window_background;
+};
+
+static void
+canvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags,
+ int x, int y, int width, int height, struct nk_color background_color)
+{
+ /* save style properties which will be overwritten */
+ canvas->panel_padding = ctx->style.window.padding;
+ canvas->item_spacing = ctx->style.window.spacing;
+ canvas->window_background = ctx->style.window.fixed_background;
+
+ /* use the complete window space and set background */
+ ctx->style.window.spacing = nk_vec2(0,0);
+ ctx->style.window.padding = nk_vec2(0,0);
+ ctx->style.window.fixed_background = nk_style_item_color(background_color);
+
+ /* create/update window and set position + size */
+ flags = flags & ~NK_WINDOW_DYNAMIC;
+ nk_begin(ctx, "Window", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags);
+ nk_window_set_bounds(ctx, nk_rect(x, y, width, height));
+
+ /* allocate the complete window space for drawing */
+ {struct nk_rect total_space;
+ total_space = nk_window_get_content_region(ctx);
+ nk_layout_row_dynamic(ctx, total_space.h, 1);
+ nk_widget(&total_space, ctx);
+ canvas->painter = nk_window_get_canvas(ctx);}
+}
+
+static void
+canvas_end(struct nk_context *ctx, struct nk_canvas *canvas)
+{
+ nk_end(ctx);
+ ctx->style.window.spacing = canvas->panel_padding;
+ ctx->style.window.padding = canvas->item_spacing;
+ ctx->style.window.fixed_background = canvas->window_background;
+}
+
+int main(int argc, char *argv[])
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct nk_context ctx;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwSetWindowUserPointer(win, &ctx);
+ glfwSetCharCallback(win, text_input);
+ glfwSetScrollCallback(win, scroll_input);
+ glfwGetWindowSize(win, &width, &height);
+
+ /* OpenGL */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ /* GUI */
+ {device_init(&device);
+ {const void *image; int w, h;
+ struct nk_font *font;
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ font = nk_font_atlas_add_default(&atlas, 13, 0);
+ image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ device_upload_atlas(&device, image, w, h);
+ nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);
+ nk_init_default(&ctx, &font->handle);
+
+ glEnable(GL_TEXTURE_2D);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* input */
+ pump_input(&ctx, win);
+
+ /* draw */
+ {struct nk_canvas canvas;
+ canvas_begin(&ctx, &canvas, 0, 0, 0, width, height, nk_rgb(250,250,250));
+ {
+ nk_fill_rect(canvas.painter, nk_rect(15,15,210,210), 5, nk_rgb(247, 230, 154));
+ nk_fill_rect(canvas.painter, nk_rect(20,20,200,200), 5, nk_rgb(188, 174, 118));
+ nk_draw_text(canvas.painter, nk_rect(30, 30, 150, 20), "Text to draw", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0));
+ nk_fill_rect(canvas.painter, nk_rect(250,20,100,100), 0, nk_rgb(0,0,255));
+ nk_fill_circle(canvas.painter, nk_rect(20,250,100,100), nk_rgb(255,0,0));
+ nk_fill_triangle(canvas.painter, 250, 250, 350, 250, 300, 350, nk_rgb(0,255,0));
+ nk_fill_arc(canvas.painter, 300, 180, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0));
+
+ {float points[12];
+ points[0] = 200; points[1] = 250;
+ points[2] = 250; points[3] = 350;
+ points[4] = 225; points[5] = 350;
+ points[6] = 200; points[7] = 300;
+ points[8] = 175; points[9] = 350;
+ points[10] = 150; points[11] = 350;
+ nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));}
+
+ nk_stroke_line(canvas.painter, 15, 10, 200, 10, 2.0f, nk_rgb(189,45,75));
+ nk_stroke_rect(canvas.painter, nk_rect(370, 20, 100, 100), 10, 3, nk_rgb(0,0,255));
+ nk_stroke_curve(canvas.painter, 380, 200, 405, 270, 455, 120, 480, 200, 2, nk_rgb(0,150,220));
+ nk_stroke_circle(canvas.painter, nk_rect(20, 370, 100, 100), 5, nk_rgb(0,255,120));
+ nk_stroke_triangle(canvas.painter, 370, 250, 470, 250, 420, 350, 6, nk_rgb(255,0,143));
+ }
+ canvas_end(&ctx, &canvas);}
+
+ /* Draw */
+ glfwGetWindowSize(win, &width, &height);
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
+ glfwSwapBuffers(win);
+ }}}
+ nk_font_atlas_clear(&atlas);
+ nk_free(&ctx);
+ device_shutdown(&device);
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/example/extended.c b/nuklear/example/extended.c
new file mode 100644
index 0000000..e555d65
--- /dev/null
+++ b/nuklear/example/extended.c
@@ -0,0 +1,906 @@
+/* nuklear - v1.05 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+struct media {
+ struct nk_font *font_14;
+ struct nk_font *font_18;
+ struct nk_font *font_20;
+ struct nk_font *font_22;
+
+ struct nk_image unchecked;
+ struct nk_image checked;
+ struct nk_image rocket;
+ struct nk_image cloud;
+ struct nk_image pen;
+ struct nk_image play;
+ struct nk_image pause;
+ struct nk_image stop;
+ struct nk_image prev;
+ struct nk_image next;
+ struct nk_image tools;
+ struct nk_image dir;
+ struct nk_image copy;
+ struct nk_image convert;
+ struct nk_image del;
+ struct nk_image edit;
+ struct nk_image images[9];
+ struct nk_image menu[6];
+};
+
+/* ===============================================================
+ *
+ * CUSTOM WIDGET
+ *
+ * ===============================================================*/
+static int
+ui_piemenu(struct nk_context *ctx, struct nk_vec2 pos, float radius,
+ struct nk_image *icons, int item_count)
+{
+ int ret = -1;
+ struct nk_rect total_space;
+ struct nk_rect bounds;
+ int active_item = 0;
+
+ /* pie menu popup */
+ struct nk_color border = ctx->style.window.border_color;
+ struct nk_style_item background = ctx->style.window.fixed_background;
+ ctx->style.window.fixed_background = nk_style_item_hide();
+ ctx->style.window.border_color = nk_rgba(0,0,0,0);
+
+ total_space = nk_window_get_content_region(ctx);
+ ctx->style.window.spacing = nk_vec2(0,0);
+ ctx->style.window.padding = nk_vec2(0,0);
+
+ if (nk_popup_begin(ctx, NK_POPUP_STATIC, "piemenu", NK_WINDOW_NO_SCROLLBAR,
+ nk_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y,
+ 2*radius,2*radius)))
+ {
+ int i = 0;
+ struct nk_command_buffer* out = nk_window_get_canvas(ctx);
+ const struct nk_input *in = &ctx->input;
+
+ total_space = nk_window_get_content_region(ctx);
+ ctx->style.window.spacing = nk_vec2(4,4);
+ ctx->style.window.padding = nk_vec2(8,8);
+ nk_layout_row_dynamic(ctx, total_space.h, 1);
+ nk_widget(&bounds, ctx);
+
+ /* outer circle */
+ nk_fill_circle(out, bounds, nk_rgb(50,50,50));
+ {
+ /* circle buttons */
+ float step = (2 * 3.141592654f) / (float)(MAX(1,item_count));
+ float a_min = 0; float a_max = step;
+
+ struct nk_vec2 center = nk_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f);
+ struct nk_vec2 drag = nk_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y);
+ float angle = (float)atan2(drag.y, drag.x);
+ if (angle < -0.0f) angle += 2.0f * 3.141592654f;
+ active_item = (int)(angle/step);
+
+ for (i = 0; i < item_count; ++i) {
+ struct nk_rect content;
+ float rx, ry, dx, dy, a;
+ nk_fill_arc(out, center.x, center.y, (bounds.w/2.0f),
+ a_min, a_max, (active_item == i) ? nk_rgb(45,100,255): nk_rgb(60,60,60));
+
+ /* separator line */
+ rx = bounds.w/2.0f; ry = 0;
+ dx = rx * (float)cos(a_min) - ry * (float)sin(a_min);
+ dy = rx * (float)sin(a_min) + ry * (float)cos(a_min);
+ nk_stroke_line(out, center.x, center.y,
+ center.x + dx, center.y + dy, 1.0f, nk_rgb(50,50,50));
+
+ /* button content */
+ a = a_min + (a_max - a_min)/2.0f;
+ rx = bounds.w/2.5f; ry = 0;
+ content.w = 30; content.h = 30;
+ content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f);
+ content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f);
+ nk_draw_image(out, content, &icons[i], nk_rgb(255,255,255));
+ a_min = a_max; a_max += step;
+ }
+ }
+ {
+ /* inner circle */
+ struct nk_rect inner;
+ inner.x = bounds.x + bounds.w/2 - bounds.w/4;
+ inner.y = bounds.y + bounds.h/2 - bounds.h/4;
+ inner.w = bounds.w/2; inner.h = bounds.h/2;
+ nk_fill_circle(out, inner, nk_rgb(45,45,45));
+
+ /* active icon content */
+ bounds.w = inner.w / 2.0f;
+ bounds.h = inner.h / 2.0f;
+ bounds.x = inner.x + inner.w/2 - bounds.w/2;
+ bounds.y = inner.y + inner.h/2 - bounds.h/2;
+ nk_draw_image(out, bounds, &icons[active_item], nk_rgb(255,255,255));
+ }
+ nk_layout_space_end(ctx);
+ if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT)) {
+ nk_popup_close(ctx);
+ ret = active_item;
+ }
+ } else ret = -2;
+ ctx->style.window.spacing = nk_vec2(4,4);
+ ctx->style.window.padding = nk_vec2(8,8);
+ nk_popup_end(ctx);
+
+ ctx->style.window.fixed_background = background;
+ ctx->style.window.border_color = border;
+ return ret;
+}
+
+/* ===============================================================
+ *
+ * GRID
+ *
+ * ===============================================================*/
+static void
+grid_demo(struct nk_context *ctx, struct media *media)
+{
+ static char text[3][64];
+ static int text_len[3];
+ static const char *items[] = {"Item 0","item 1","item 2"};
+ static int selected_item = 0;
+ static int check = 1;
+
+ int i;
+ nk_style_set_font(ctx, &media->font_20->handle);
+ if (nk_begin(ctx, "Grid Demo", nk_rect(600, 350, 275, 250),
+ NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|
+ NK_WINDOW_NO_SCROLLBAR))
+ {
+ nk_style_set_font(ctx, &media->font_18->handle);
+ nk_layout_row_dynamic(ctx, 30, 2);
+ nk_label(ctx, "Floating point:", NK_TEXT_RIGHT);
+ nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float);
+ nk_label(ctx, "Hexadecimal:", NK_TEXT_RIGHT);
+ nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex);
+ nk_label(ctx, "Binary:", NK_TEXT_RIGHT);
+ nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary);
+ nk_label(ctx, "Checkbox:", NK_TEXT_RIGHT);
+ nk_checkbox_label(ctx, "Check me", &check);
+ nk_label(ctx, "Combobox:", NK_TEXT_RIGHT);
+ if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {
+ nk_layout_row_dynamic(ctx, 25, 1);
+ for (i = 0; i < 3; ++i)
+ if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
+ selected_item = i;
+ nk_combo_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ nk_style_set_font(ctx, &media->font_14->handle);
+}
+
+/* ===============================================================
+ *
+ * BUTTON DEMO
+ *
+ * ===============================================================*/
+static void
+ui_header(struct nk_context *ctx, struct media *media, const char *title)
+{
+ nk_style_set_font(ctx, &media->font_18->handle);
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, title, NK_TEXT_LEFT);
+}
+
+static void
+ui_widget(struct nk_context *ctx, struct media *media, float height)
+{
+ static const float ratio[] = {0.15f, 0.85f};
+ nk_style_set_font(ctx, &media->font_22->handle);
+ nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);
+ nk_spacing(ctx, 1);
+}
+
+static void
+ui_widget_centered(struct nk_context *ctx, struct media *media, float height)
+{
+ static const float ratio[] = {0.15f, 0.50f, 0.35f};
+ nk_style_set_font(ctx, &media->font_22->handle);
+ nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio);
+ nk_spacing(ctx, 1);
+}
+
+static void
+button_demo(struct nk_context *ctx, struct media *media)
+{
+ static int option = 1;
+ static int toggle0 = 1;
+ static int toggle1 = 0;
+ static int toggle2 = 1;
+
+ nk_style_set_font(ctx, &media->font_20->handle);
+ nk_begin(ctx, "Button Demo", nk_rect(50,50,255,610),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);
+
+ /*------------------------------------------------
+ * MENU
+ *------------------------------------------------*/
+ nk_menubar_begin(ctx);
+ {
+ /* toolbar */
+ nk_layout_row_static(ctx, 40, 40, 4);
+ if (nk_menu_begin_image(ctx, "Music", media->play, nk_vec2(110,120)))
+ {
+ /* settings */
+ nk_layout_row_dynamic(ctx, 25, 1);
+ nk_menu_item_image_label(ctx, media->play, "Play", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->stop, "Stop", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->pause, "Pause", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->next, "Next", NK_TEXT_RIGHT);
+ nk_menu_item_image_label(ctx, media->prev, "Prev", NK_TEXT_RIGHT);
+ nk_menu_end(ctx);
+ }
+ nk_button_image(ctx, media->tools);
+ nk_button_image(ctx, media->cloud);
+ nk_button_image(ctx, media->pen);
+ }
+ nk_menubar_end(ctx);
+
+ /*------------------------------------------------
+ * BUTTON
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Push buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_label(ctx, "Push me"))
+ fprintf(stdout, "pushed!\n");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, media->rocket, "Styled", NK_TEXT_CENTERED))
+ fprintf(stdout, "rocket!\n");
+
+ /*------------------------------------------------
+ * REPEATER
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Repeater");
+ ui_widget(ctx, media, 35);
+ if (nk_button_label(ctx, "Press me"))
+ fprintf(stdout, "pressed!\n");
+
+ /*------------------------------------------------
+ * TOGGLE
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Toggle buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle0) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle0 = !toggle0;
+
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle1) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle1 = !toggle1;
+
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, (toggle2) ? media->checked: media->unchecked, "Toggle", NK_TEXT_LEFT))
+ toggle2 = !toggle2;
+
+ /*------------------------------------------------
+ * RADIO
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Radio buttons");
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 0;
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 1;
+ ui_widget(ctx, media, 35);
+ if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, "Select", NK_TEXT_LEFT))
+ option = 2;
+
+ /*------------------------------------------------
+ * CONTEXTUAL
+ *------------------------------------------------*/
+ nk_style_set_font(ctx, &media->font_18->handle);
+ if (nk_contextual_begin(ctx, NK_WINDOW_NO_SCROLLBAR, nk_vec2(150, 300), nk_window_get_bounds(ctx))) {
+ nk_layout_row_dynamic(ctx, 30, 1);
+ if (nk_contextual_item_image_label(ctx, media->copy, "Clone", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed clone!\n");
+ if (nk_contextual_item_image_label(ctx, media->del, "Delete", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed delete!\n");
+ if (nk_contextual_item_image_label(ctx, media->convert, "Convert", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed convert!\n");
+ if (nk_contextual_item_image_label(ctx, media->edit, "Edit", NK_TEXT_RIGHT))
+ fprintf(stdout, "pressed edit!\n");
+ nk_contextual_end(ctx);
+ }
+ nk_style_set_font(ctx, &media->font_14->handle);
+ nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ * BASIC DEMO
+ *
+ * ===============================================================*/
+static void
+basic_demo(struct nk_context *ctx, struct media *media)
+{
+ static int image_active;
+ static int check0 = 1;
+ static int check1 = 0;
+ static size_t prog = 80;
+ static int selected_item = 0;
+ static int selected_image = 3;
+ static int selected_icon = 0;
+ static const char *items[] = {"Item 0","item 1","item 2"};
+ static int piemenu_active = 0;
+ static struct nk_vec2 piemenu_pos;
+
+ int i = 0;
+ nk_style_set_font(ctx, &media->font_20->handle);
+ nk_begin(ctx, "Basic Demo", nk_rect(320, 50, 275, 610),
+ NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);
+
+ /*------------------------------------------------
+ * POPUP BUTTON
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Popup & Scrollbar & Images");
+ ui_widget(ctx, media, 35);
+ if (nk_button_image_label(ctx, media->dir, "Images", NK_TEXT_CENTERED))
+ image_active = !image_active;
+
+ /*------------------------------------------------
+ * SELECTED IMAGE
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Selected Image");
+ ui_widget_centered(ctx, media, 100);
+ nk_image(ctx, media->images[selected_image]);
+
+ /*------------------------------------------------
+ * IMAGE POPUP
+ *------------------------------------------------*/
+ if (image_active) {
+ struct nk_panel popup;
+ if (nk_popup_begin(ctx, NK_POPUP_STATIC, "Image Popup", 0, nk_rect(265, 0, 320, 220))) {
+ nk_layout_row_static(ctx, 82, 82, 3);
+ for (i = 0; i < 9; ++i) {
+ if (nk_button_image(ctx, media->images[i])) {
+ selected_image = i;
+ image_active = 0;
+ nk_popup_close(ctx);
+ }
+ }
+ nk_popup_end(ctx);
+ }
+ }
+ /*------------------------------------------------
+ * COMBOBOX
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Combo box");
+ ui_widget(ctx, media, 40);
+ if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {
+ nk_layout_row_dynamic(ctx, 35, 1);
+ for (i = 0; i < 3; ++i)
+ if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
+ selected_item = i;
+ nk_combo_end(ctx);
+ }
+
+ ui_widget(ctx, media, 40);
+ if (nk_combo_begin_image_label(ctx, items[selected_icon], media->images[selected_icon], nk_vec2(nk_widget_width(ctx), 200))) {
+ nk_layout_row_dynamic(ctx, 35, 1);
+ for (i = 0; i < 3; ++i)
+ if (nk_combo_item_image_label(ctx, media->images[i], items[i], NK_TEXT_RIGHT))
+ selected_icon = i;
+ nk_combo_end(ctx);
+ }
+
+ /*------------------------------------------------
+ * CHECKBOX
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Checkbox");
+ ui_widget(ctx, media, 30);
+ nk_checkbox_label(ctx, "Flag 1", &check0);
+ ui_widget(ctx, media, 30);
+ nk_checkbox_label(ctx, "Flag 2", &check1);
+
+ /*------------------------------------------------
+ * PROGRESSBAR
+ *------------------------------------------------*/
+ ui_header(ctx, media, "Progressbar");
+ ui_widget(ctx, media, 35);
+ nk_progress(ctx, &prog, 100, nk_true);
+
+ /*------------------------------------------------
+ * PIEMENU
+ *------------------------------------------------*/
+ if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT,
+ nk_window_get_bounds(ctx),nk_true)){
+ piemenu_pos = ctx->input.mouse.pos;
+ piemenu_active = 1;
+ }
+
+ if (piemenu_active) {
+ int ret = ui_piemenu(ctx, piemenu_pos, 140, &media->menu[0], 6);
+ if (ret == -2) piemenu_active = 0;
+ if (ret != -1) {
+ fprintf(stdout, "piemenu selected: %d\n", ret);
+ piemenu_active = 0;
+ }
+ }
+ nk_style_set_font(ctx, &media->font_14->handle);
+ nk_end(ctx);
+}
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static struct nk_image
+icon_load(const char *filename)
+{
+ int x,y,n;
+ GLuint tex;
+ unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+ if (!data) die("[SDL]: failed to load image: %s", filename);
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ return nk_image_id((int)tex);
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+ nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+ nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+ int display_width=0, display_height=0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct media media;
+ struct nk_context ctx;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwSetWindowUserPointer(win, &ctx);
+ glfwSetCharCallback(win, text_input);
+ glfwSetScrollCallback(win, scroll_input);
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+
+ /* OpenGL */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ {/* GUI */
+ device_init(&device);
+ {const void *image; int w, h;
+ struct nk_font_config cfg = nk_font_config(0);
+ cfg.oversample_h = 3; cfg.oversample_v = 2;
+ /* Loading one font with different heights is only required if you want higher
+ * quality text otherwise you can just set the font height directly
+ * e.g.: ctx->style.font.height = 20. */
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ media.font_14 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 14.0f, &cfg);
+ media.font_18 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 18.0f, &cfg);
+ media.font_20 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 20.0f, &cfg);
+ media.font_22 = nk_font_atlas_add_from_file(&atlas, "../../extra_font/Roboto-Regular.ttf", 22.0f, &cfg);
+ image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ device_upload_atlas(&device, image, w, h);
+ nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+ nk_init_default(&ctx, &media.font_14->handle);}
+
+ /* icons */
+ glEnable(GL_TEXTURE_2D);
+ media.unchecked = icon_load("../icon/unchecked.png");
+ media.checked = icon_load("../icon/checked.png");
+ media.rocket = icon_load("../icon/rocket.png");
+ media.cloud = icon_load("../icon/cloud.png");
+ media.pen = icon_load("../icon/pen.png");
+ media.play = icon_load("../icon/play.png");
+ media.pause = icon_load("../icon/pause.png");
+ media.stop = icon_load("../icon/stop.png");
+ media.next = icon_load("../icon/next.png");
+ media.prev = icon_load("../icon/prev.png");
+ media.tools = icon_load("../icon/tools.png");
+ media.dir = icon_load("../icon/directory.png");
+ media.copy = icon_load("../icon/copy.png");
+ media.convert = icon_load("../icon/export.png");
+ media.del = icon_load("../icon/delete.png");
+ media.edit = icon_load("../icon/edit.png");
+ media.menu[0] = icon_load("../icon/home.png");
+ media.menu[1] = icon_load("../icon/phone.png");
+ media.menu[2] = icon_load("../icon/plane.png");
+ media.menu[3] = icon_load("../icon/wifi.png");
+ media.menu[4] = icon_load("../icon/settings.png");
+ media.menu[5] = icon_load("../icon/volume.png");
+
+ {int i;
+ for (i = 0; i < 9; ++i) {
+ char buffer[256];
+ sprintf(buffer, "../images/image%d.png", (i+1));
+ media.images[i] = icon_load(buffer);
+ }}
+
+ while (!glfwWindowShouldClose(win))
+ {
+ /* High DPI displays */
+ struct nk_vec2 scale;
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* Input */
+ {double x, y;
+ nk_input_begin(&ctx);
+ glfwPollEvents();
+ nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+ if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+ glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
+ nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+ } else {
+ nk_input_key(&ctx, NK_KEY_COPY, 0);
+ nk_input_key(&ctx, NK_KEY_PASTE, 0);
+ nk_input_key(&ctx, NK_KEY_CUT, 0);
+ nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+ }
+ glfwGetCursorPos(win, &x, &y);
+ nk_input_motion(&ctx, (int)x, (int)y);
+ nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_end(&ctx);}
+
+ /* GUI */
+ basic_demo(&ctx, &media);
+ button_demo(&ctx, &media);
+ grid_demo(&ctx, &media);
+
+ /* Draw */
+ glViewport(0, 0, display_width, display_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
+ device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+ glfwSwapBuffers(win);
+ }
+
+ glDeleteTextures(1,(const GLuint*)&media.unchecked.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.checked.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.rocket.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.cloud.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.pen.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.play.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.pause.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.stop.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.next.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.prev.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.tools.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.dir.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.del.handle.id);
+
+ nk_font_atlas_clear(&atlas);
+ nk_free(&ctx);
+
+ device_shutdown(&device);
+ glfwTerminate();
+ return 0;
+}
+
diff --git a/nuklear/example/file_browser.c b/nuklear/example/file_browser.c
new file mode 100644
index 0000000..ece4cb8
--- /dev/null
+++ b/nuklear/example/file_browser.c
@@ -0,0 +1,910 @@
+/* nuklear - v1.05 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+/* ===============================================================
+ *
+ * GUI
+ *
+ * ===============================================================*/
+struct icons {
+ struct nk_image desktop;
+ struct nk_image home;
+ struct nk_image computer;
+ struct nk_image directory;
+
+ struct nk_image default_file;
+ struct nk_image text_file;
+ struct nk_image music_file;
+ struct nk_image font_file;
+ struct nk_image img_file;
+ struct nk_image movie_file;
+};
+
+enum file_groups {
+ FILE_GROUP_DEFAULT,
+ FILE_GROUP_TEXT,
+ FILE_GROUP_MUSIC,
+ FILE_GROUP_FONT,
+ FILE_GROUP_IMAGE,
+ FILE_GROUP_MOVIE,
+ FILE_GROUP_MAX
+};
+
+enum file_types {
+ FILE_DEFAULT,
+ FILE_TEXT,
+ FILE_C_SOURCE,
+ FILE_CPP_SOURCE,
+ FILE_HEADER,
+ FILE_CPP_HEADER,
+ FILE_MP3,
+ FILE_WAV,
+ FILE_OGG,
+ FILE_TTF,
+ FILE_BMP,
+ FILE_PNG,
+ FILE_JPEG,
+ FILE_PCX,
+ FILE_TGA,
+ FILE_GIF,
+ FILE_MAX
+};
+
+struct file_group {
+ enum file_groups group;
+ const char *name;
+ struct nk_image *icon;
+};
+
+struct file {
+ enum file_types type;
+ const char *suffix;
+ enum file_groups group;
+};
+
+struct media {
+ int font;
+ int icon_sheet;
+ struct icons icons;
+ struct file_group group[FILE_GROUP_MAX];
+ struct file files[FILE_MAX];
+};
+
+#define MAX_PATH_LEN 512
+struct file_browser {
+ /* path */
+ char file[MAX_PATH_LEN];
+ char home[MAX_PATH_LEN];
+ char desktop[MAX_PATH_LEN];
+ char directory[MAX_PATH_LEN];
+
+ /* directory content */
+ char **files;
+ char **directories;
+ size_t file_count;
+ size_t dir_count;
+ struct media *media;
+};
+
+#ifdef __unix__
+#include <dirent.h>
+#include <unistd.h>
+#endif
+
+#ifndef _WIN32
+# include <pwd.h>
+#endif
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static char*
+file_load(const char* path, size_t* siz)
+{
+ char *buf;
+ FILE *fd = fopen(path, "rb");
+ if (!fd) die("Failed to open file: %s\n", path);
+ fseek(fd, 0, SEEK_END);
+ *siz = (size_t)ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ buf = (char*)calloc(*siz, 1);
+ fread(buf, *siz, 1, fd);
+ fclose(fd);
+ return buf;
+}
+
+static char*
+str_duplicate(const char *src)
+{
+ char *ret;
+ size_t len = strlen(src);
+ if (!len) return 0;
+ ret = (char*)malloc(len+1);
+ if (!ret) return 0;
+ memcpy(ret, src, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+static void
+dir_free_list(char **list, size_t size)
+{
+ size_t i;
+ for (i = 0; i < size; ++i)
+ free(list[i]);
+ free(list);
+}
+
+static char**
+dir_list(const char *dir, int return_subdirs, size_t *count)
+{
+ size_t n = 0;
+ char buffer[MAX_PATH_LEN];
+ char **results = NULL;
+ const DIR *none = NULL;
+ size_t capacity = 32;
+ size_t size;
+ DIR *z;
+
+ assert(dir);
+ assert(count);
+ strncpy(buffer, dir, MAX_PATH_LEN);
+ n = strlen(buffer);
+
+ if (n > 0 && (buffer[n-1] != '/'))
+ buffer[n++] = '/';
+
+ size = 0;
+
+ z = opendir(dir);
+ if (z != none) {
+ int nonempty = 1;
+ struct dirent *data = readdir(z);
+ nonempty = (data != NULL);
+ if (!nonempty) return NULL;
+
+ do {
+ DIR *y;
+ char *p;
+ int is_subdir;
+ if (data->d_name[0] == '.')
+ continue;
+
+ strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);
+ y = opendir(buffer);
+ is_subdir = (y != NULL);
+ if (y != NULL) closedir(y);
+
+ if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){
+ if (!size) {
+ results = (char**)calloc(sizeof(char*), capacity);
+ } else if (size >= capacity) {
+ void *old = results;
+ capacity = capacity * 2;
+ results = (char**)realloc(results, capacity * sizeof(char*));
+ assert(results);
+ if (!results) free(old);
+ }
+ p = str_duplicate(data->d_name);
+ results[size++] = p;
+ }
+ } while ((data = readdir(z)) != NULL);
+ }
+
+ if (z) closedir(z);
+ *count = size;
+ return results;
+}
+
+static struct file_group
+FILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon)
+{
+ struct file_group fg;
+ fg.group = group;
+ fg.name = name;
+ fg.icon = icon;
+ return fg;
+}
+
+static struct file
+FILE_DEF(enum file_types type, const char *suffix, enum file_groups group)
+{
+ struct file fd;
+ fd.type = type;
+ fd.suffix = suffix;
+ fd.group = group;
+ return fd;
+}
+
+static struct nk_image*
+media_icon_for_file(struct media *media, const char *file)
+{
+ int i = 0;
+ const char *s = file;
+ char suffix[4];
+ int found = 0;
+ memset(suffix, 0, sizeof(suffix));
+
+ /* extract suffix .xxx from file */
+ while (*s++ != '\0') {
+ if (found && i < 3)
+ suffix[i++] = *s;
+
+ if (*s == '.') {
+ if (found){
+ found = 0;
+ break;
+ }
+ found = 1;
+ }
+ }
+
+ /* check for all file definition of all groups for fitting suffix*/
+ for (i = 0; i < FILE_MAX && found; ++i) {
+ struct file *d = &media->files[i];
+ {
+ const char *f = d->suffix;
+ s = suffix;
+ while (f && *f && *s && *s == *f) {
+ s++; f++;
+ }
+
+ /* found correct file definition so */
+ if (f && *s == '\0' && *f == '\0')
+ return media->group[d->group].icon;
+ }
+ }
+ return &media->icons.default_file;
+}
+
+static void
+media_init(struct media *media)
+{
+ /* file groups */
+ struct icons *icons = &media->icons;
+ media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file);
+ media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file);
+ media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file);
+ media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file);
+ media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file);
+ media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file);
+
+ /* files */
+ media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);
+ media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT);
+ media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT);
+ media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT);
+ media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT);
+ media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT);
+ media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC);
+ media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC);
+ media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC);
+ media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT);
+ media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE);
+ media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE);
+ media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE);
+ media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE);
+ media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE);
+ media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE);
+}
+
+static void
+file_browser_reload_directory_content(struct file_browser *browser, const char *path)
+{
+ strncpy(browser->directory, path, MAX_PATH_LEN);
+ dir_free_list(browser->files, browser->file_count);
+ dir_free_list(browser->directories, browser->dir_count);
+ browser->files = dir_list(path, 0, &browser->file_count);
+ browser->directories = dir_list(path, 1, &browser->dir_count);
+}
+
+static void
+file_browser_init(struct file_browser *browser, struct media *media)
+{
+ memset(browser, 0, sizeof(*browser));
+ browser->media = media;
+ {
+ /* load files and sub-directory list */
+ const char *home = getenv("HOME");
+#ifdef _WIN32
+ if (!home) home = getenv("USERPROFILE");
+#else
+ if (!home) home = getpwuid(getuid())->pw_dir;
+ {
+ size_t l;
+ strncpy(browser->home, home, MAX_PATH_LEN);
+ l = strlen(browser->home);
+ strcpy(browser->home + l, "/");
+ strcpy(browser->directory, browser->home);
+ }
+#endif
+ {
+ size_t l;
+ strcpy(browser->desktop, browser->home);
+ l = strlen(browser->desktop);
+ strcpy(browser->desktop + l, "desktop/");
+ }
+ browser->files = dir_list(browser->directory, 0, &browser->file_count);
+ browser->directories = dir_list(browser->directory, 1, &browser->dir_count);
+ }
+}
+
+static void
+file_browser_free(struct file_browser *browser)
+{
+ if (browser->files)
+ dir_free_list(browser->files, browser->file_count);
+ if (browser->directories)
+ dir_free_list(browser->directories, browser->dir_count);
+ browser->files = NULL;
+ browser->directories = NULL;
+ memset(browser, 0, sizeof(*browser));
+}
+
+static int
+file_browser_run(struct file_browser *browser, struct nk_context *ctx)
+{
+ int ret = 0;
+ struct media *media = browser->media;
+ struct nk_rect total_space;
+
+ if (nk_begin(ctx, "File Browser", nk_rect(50, 50, 800, 600),
+ NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
+ {
+ static float ratio[] = {0.25f, NK_UNDEFINED};
+ float spacing_x = ctx->style.window.spacing.x;
+
+ /* output path directory selector in the menubar */
+ ctx->style.window.spacing.x = 0;
+ nk_menubar_begin(ctx);
+ {
+ char *d = browser->directory;
+ char *begin = d + 1;
+ nk_layout_row_dynamic(ctx, 25, 6);
+ while (*d++) {
+ if (*d == '/') {
+ *d = '\0';
+ if (nk_button_label(ctx, begin)) {
+ *d++ = '/'; *d = '\0';
+ file_browser_reload_directory_content(browser, browser->directory);
+ break;
+ }
+ *d = '/';
+ begin = d + 1;
+ }
+ }
+ }
+ nk_menubar_end(ctx);
+ ctx->style.window.spacing.x = spacing_x;
+
+ /* window layout */
+ total_space = nk_window_get_content_region(ctx);
+ nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio);
+ nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR);
+ {
+ struct nk_image home = media->icons.home;
+ struct nk_image desktop = media->icons.desktop;
+ struct nk_image computer = media->icons.computer;
+
+ nk_layout_row_dynamic(ctx, 40, 1);
+ if (nk_button_image_label(ctx, home, "home", NK_TEXT_CENTERED))
+ file_browser_reload_directory_content(browser, browser->home);
+ if (nk_button_image_label(ctx,desktop,"desktop",NK_TEXT_CENTERED))
+ file_browser_reload_directory_content(browser, browser->desktop);
+ if (nk_button_image_label(ctx,computer,"computer",NK_TEXT_CENTERED))
+ file_browser_reload_directory_content(browser, "/");
+ nk_group_end(ctx);
+ }
+
+ /* output directory content window */
+ nk_group_begin(ctx, "Content", 0);
+ {
+ int index = -1;
+ size_t i = 0, j = 0, k = 0;
+ size_t rows = 0, cols = 0;
+ size_t count = browser->dir_count + browser->file_count;
+
+ cols = 4;
+ rows = count / cols;
+ for (i = 0; i <= rows; i += 1) {
+ {size_t n = j + cols;
+ nk_layout_row_dynamic(ctx, 135, (int)cols);
+ for (; j < count && j < n; ++j) {
+ /* draw one row of icons */
+ if (j < browser->dir_count) {
+ /* draw and execute directory buttons */
+ if (nk_button_image(ctx,media->icons.directory))
+ index = (int)j;
+ } else {
+ /* draw and execute files buttons */
+ struct nk_image *icon;
+ size_t fileIndex = ((size_t)j - browser->dir_count);
+ icon = media_icon_for_file(media,browser->files[fileIndex]);
+ if (nk_button_image(ctx, *icon)) {
+ strncpy(browser->file, browser->directory, MAX_PATH_LEN);
+ n = strlen(browser->file);
+ strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);
+ ret = 1;
+ }
+ }
+ }}
+ {size_t n = k + cols;
+ nk_layout_row_dynamic(ctx, 20, (int)cols);
+ for (; k < count && k < n; k++) {
+ /* draw one row of labels */
+ if (k < browser->dir_count) {
+ nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED);
+ } else {
+ size_t t = k-browser->dir_count;
+ nk_label(ctx,browser->files[t],NK_TEXT_CENTERED);
+ }
+ }}
+ }
+
+ if (index != -1) {
+ size_t n = strlen(browser->directory);
+ strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);
+ n = strlen(browser->directory);
+ if (n < MAX_PATH_LEN - 1) {
+ browser->directory[n] = '/';
+ browser->directory[n+1] = '\0';
+ }
+ file_browser_reload_directory_content(browser, browser->directory);
+ }
+ nk_group_end(ctx);
+ }
+ }
+ nk_end(ctx);
+ return ret;
+}
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+static struct nk_image
+icon_load(const char *filename)
+{
+ int x,y,n;
+ GLuint tex;
+ unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+ if (!data) die("[SDL]: failed to load image: %s", filename);
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ return nk_image_id((int)tex);
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+ nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+ nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, ctx, &dev->cmds) {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+ int display_width = 0, display_height = 0;
+
+ /* GUI */
+ struct device device;
+ struct nk_context ctx;
+ struct nk_font *font;
+ struct nk_font_atlas atlas;
+ struct file_browser browser;
+ struct media media;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwSetWindowUserPointer(win, &ctx);
+ glfwSetCharCallback(win, text_input);
+ glfwSetScrollCallback(win, scroll_input);
+
+ /* OpenGL */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ {/* GUI */
+ device_init(&device);
+ {const void *image; int w, h;
+ const char *font_path = (argc > 1) ? argv[1]: 0;
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 13.0f, NULL);
+ else font = nk_font_atlas_add_default(&atlas, 13.0f, NULL);
+ image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ device_upload_atlas(&device, image, w, h);
+ nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
+ nk_init_default(&ctx, &font->handle);}
+
+ /* icons */
+ glEnable(GL_TEXTURE_2D);
+ media.icons.home = icon_load("../icon/home.png");
+ media.icons.directory = icon_load("../icon/directory.png");
+ media.icons.computer = icon_load("../icon/computer.png");
+ media.icons.desktop = icon_load("../icon/desktop.png");
+ media.icons.default_file = icon_load("../icon/default.png");
+ media.icons.text_file = icon_load("../icon/text.png");
+ media.icons.music_file = icon_load("../icon/music.png");
+ media.icons.font_file = icon_load("../icon/font.png");
+ media.icons.img_file = icon_load("../icon/img.png");
+ media.icons.movie_file = icon_load("../icon/movie.png");
+ media_init(&media);
+
+ file_browser_init(&browser, &media);
+ while (!glfwWindowShouldClose(win))
+ {
+ /* High DPI displays */
+ struct nk_vec2 scale;
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+ scale.x = (float)display_width/(float)width;
+ scale.y = (float)display_height/(float)height;
+
+ /* Input */
+ {double x, y;
+ nk_input_begin(&ctx);
+ glfwPollEvents();
+ nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
+ if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
+ glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {
+ nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
+ nk_input_key(&ctx, NK_KEY_SHIFT, 1);
+ } else {
+ nk_input_key(&ctx, NK_KEY_COPY, 0);
+ nk_input_key(&ctx, NK_KEY_PASTE, 0);
+ nk_input_key(&ctx, NK_KEY_CUT, 0);
+ nk_input_key(&ctx, NK_KEY_SHIFT, 0);
+ }
+ glfwGetCursorPos(win, &x, &y);
+ nk_input_motion(&ctx, (int)x, (int)y);
+ nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_end(&ctx);}
+
+ /* GUI */
+ file_browser_run(&browser, &ctx);
+
+ /* Draw */
+ glViewport(0, 0, display_width, display_height);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+ glfwSwapBuffers(win);
+ }
+
+ glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id);
+ glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id);
+
+ file_browser_free(&browser);
+ nk_font_atlas_clear(&atlas);
+ nk_free(&ctx);
+ device_shutdown(&device);
+ glfwTerminate();
+ return 0;
+}
+
+
diff --git a/nuklear/example/icon/checked.png b/nuklear/example/icon/checked.png
new file mode 100644
index 0000000..e4e05b2
--- /dev/null
+++ b/nuklear/example/icon/checked.png
Binary files differ
diff --git a/nuklear/example/icon/cloud.png b/nuklear/example/icon/cloud.png
new file mode 100644
index 0000000..ecc5791
--- /dev/null
+++ b/nuklear/example/icon/cloud.png
Binary files differ
diff --git a/nuklear/example/icon/computer.png b/nuklear/example/icon/computer.png
new file mode 100644
index 0000000..29db8fc
--- /dev/null
+++ b/nuklear/example/icon/computer.png
Binary files differ
diff --git a/nuklear/example/icon/copy.png b/nuklear/example/icon/copy.png
new file mode 100644
index 0000000..0a6e979
--- /dev/null
+++ b/nuklear/example/icon/copy.png
Binary files differ
diff --git a/nuklear/example/icon/default.png b/nuklear/example/icon/default.png
new file mode 100644
index 0000000..c11145a
--- /dev/null
+++ b/nuklear/example/icon/default.png
Binary files differ
diff --git a/nuklear/example/icon/delete.png b/nuklear/example/icon/delete.png
new file mode 100644
index 0000000..7bc6dde
--- /dev/null
+++ b/nuklear/example/icon/delete.png
Binary files differ
diff --git a/nuklear/example/icon/desktop.png b/nuklear/example/icon/desktop.png
new file mode 100644
index 0000000..b4abcfd
--- /dev/null
+++ b/nuklear/example/icon/desktop.png
Binary files differ
diff --git a/nuklear/example/icon/directory.png b/nuklear/example/icon/directory.png
new file mode 100644
index 0000000..4c73d37
--- /dev/null
+++ b/nuklear/example/icon/directory.png
Binary files differ
diff --git a/nuklear/example/icon/edit.png b/nuklear/example/icon/edit.png
new file mode 100644
index 0000000..62ce0b4
--- /dev/null
+++ b/nuklear/example/icon/edit.png
Binary files differ
diff --git a/nuklear/example/icon/export.png b/nuklear/example/icon/export.png
new file mode 100644
index 0000000..ff6b5aa
--- /dev/null
+++ b/nuklear/example/icon/export.png
Binary files differ
diff --git a/nuklear/example/icon/font.png b/nuklear/example/icon/font.png
new file mode 100644
index 0000000..918e9bf
--- /dev/null
+++ b/nuklear/example/icon/font.png
Binary files differ
diff --git a/nuklear/example/icon/home.png b/nuklear/example/icon/home.png
new file mode 100644
index 0000000..8560626
--- /dev/null
+++ b/nuklear/example/icon/home.png
Binary files differ
diff --git a/nuklear/example/icon/img.png b/nuklear/example/icon/img.png
new file mode 100644
index 0000000..1985957
--- /dev/null
+++ b/nuklear/example/icon/img.png
Binary files differ
diff --git a/nuklear/example/icon/movie.png b/nuklear/example/icon/movie.png
new file mode 100644
index 0000000..5227883
--- /dev/null
+++ b/nuklear/example/icon/movie.png
Binary files differ
diff --git a/nuklear/example/icon/music.png b/nuklear/example/icon/music.png
new file mode 100644
index 0000000..0f1415c
--- /dev/null
+++ b/nuklear/example/icon/music.png
Binary files differ
diff --git a/nuklear/example/icon/next.png b/nuklear/example/icon/next.png
new file mode 100644
index 0000000..af0b98d
--- /dev/null
+++ b/nuklear/example/icon/next.png
Binary files differ
diff --git a/nuklear/example/icon/pause.png b/nuklear/example/icon/pause.png
new file mode 100644
index 0000000..7d6367e
--- /dev/null
+++ b/nuklear/example/icon/pause.png
Binary files differ
diff --git a/nuklear/example/icon/pen.png b/nuklear/example/icon/pen.png
new file mode 100644
index 0000000..10c851c
--- /dev/null
+++ b/nuklear/example/icon/pen.png
Binary files differ
diff --git a/nuklear/example/icon/phone.png b/nuklear/example/icon/phone.png
new file mode 100644
index 0000000..5e6f613
--- /dev/null
+++ b/nuklear/example/icon/phone.png
Binary files differ
diff --git a/nuklear/example/icon/plane.png b/nuklear/example/icon/plane.png
new file mode 100644
index 0000000..3a98489
--- /dev/null
+++ b/nuklear/example/icon/plane.png
Binary files differ
diff --git a/nuklear/example/icon/play.png b/nuklear/example/icon/play.png
new file mode 100644
index 0000000..9c9e8f0
--- /dev/null
+++ b/nuklear/example/icon/play.png
Binary files differ
diff --git a/nuklear/example/icon/prev.png b/nuklear/example/icon/prev.png
new file mode 100644
index 0000000..0eecc2e
--- /dev/null
+++ b/nuklear/example/icon/prev.png
Binary files differ
diff --git a/nuklear/example/icon/rocket.png b/nuklear/example/icon/rocket.png
new file mode 100644
index 0000000..ea8e187
--- /dev/null
+++ b/nuklear/example/icon/rocket.png
Binary files differ
diff --git a/nuklear/example/icon/settings.png b/nuklear/example/icon/settings.png
new file mode 100644
index 0000000..e6e13f8
--- /dev/null
+++ b/nuklear/example/icon/settings.png
Binary files differ
diff --git a/nuklear/example/icon/stop.png b/nuklear/example/icon/stop.png
new file mode 100644
index 0000000..6742baf
--- /dev/null
+++ b/nuklear/example/icon/stop.png
Binary files differ
diff --git a/nuklear/example/icon/text.png b/nuklear/example/icon/text.png
new file mode 100644
index 0000000..136e534
--- /dev/null
+++ b/nuklear/example/icon/text.png
Binary files differ
diff --git a/nuklear/example/icon/tools.png b/nuklear/example/icon/tools.png
new file mode 100644
index 0000000..412ff85
--- /dev/null
+++ b/nuklear/example/icon/tools.png
Binary files differ
diff --git a/nuklear/example/icon/unchecked.png b/nuklear/example/icon/unchecked.png
new file mode 100644
index 0000000..fca94d2
--- /dev/null
+++ b/nuklear/example/icon/unchecked.png
Binary files differ
diff --git a/nuklear/example/icon/volume.png b/nuklear/example/icon/volume.png
new file mode 100644
index 0000000..8e86fa9
--- /dev/null
+++ b/nuklear/example/icon/volume.png
Binary files differ
diff --git a/nuklear/example/icon/wifi.png b/nuklear/example/icon/wifi.png
new file mode 100644
index 0000000..270d55d
--- /dev/null
+++ b/nuklear/example/icon/wifi.png
Binary files differ
diff --git a/nuklear/example/images/image1.png b/nuklear/example/images/image1.png
new file mode 100644
index 0000000..66a2b63
--- /dev/null
+++ b/nuklear/example/images/image1.png
Binary files differ
diff --git a/nuklear/example/images/image2.png b/nuklear/example/images/image2.png
new file mode 100644
index 0000000..4acafe5
--- /dev/null
+++ b/nuklear/example/images/image2.png
Binary files differ
diff --git a/nuklear/example/images/image3.png b/nuklear/example/images/image3.png
new file mode 100644
index 0000000..4dfe664
--- /dev/null
+++ b/nuklear/example/images/image3.png
Binary files differ
diff --git a/nuklear/example/images/image4.png b/nuklear/example/images/image4.png
new file mode 100644
index 0000000..d2f16d0
--- /dev/null
+++ b/nuklear/example/images/image4.png
Binary files differ
diff --git a/nuklear/example/images/image5.png b/nuklear/example/images/image5.png
new file mode 100644
index 0000000..852fd70
--- /dev/null
+++ b/nuklear/example/images/image5.png
Binary files differ
diff --git a/nuklear/example/images/image6.png b/nuklear/example/images/image6.png
new file mode 100644
index 0000000..0e261cb
--- /dev/null
+++ b/nuklear/example/images/image6.png
Binary files differ
diff --git a/nuklear/example/images/image7.png b/nuklear/example/images/image7.png
new file mode 100644
index 0000000..f61325b
--- /dev/null
+++ b/nuklear/example/images/image7.png
Binary files differ
diff --git a/nuklear/example/images/image8.png b/nuklear/example/images/image8.png
new file mode 100644
index 0000000..6b27cb8
--- /dev/null
+++ b/nuklear/example/images/image8.png
Binary files differ
diff --git a/nuklear/example/images/image9.png b/nuklear/example/images/image9.png
new file mode 100644
index 0000000..516929e
--- /dev/null
+++ b/nuklear/example/images/image9.png
Binary files differ
diff --git a/nuklear/example/skinning.c b/nuklear/example/skinning.c
new file mode 100644
index 0000000..4634b09
--- /dev/null
+++ b/nuklear/example/skinning.c
@@ -0,0 +1,825 @@
+/* nuklear - v1.05 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#include "../nuklear.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+/* macros */
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_MEMORY 512 * 1024
+#define MAX_ELEMENT_MEMORY 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+struct media {
+ GLint skin;
+ struct nk_image menu;
+ struct nk_image check;
+ struct nk_image check_cursor;
+ struct nk_image option;
+ struct nk_image option_cursor;
+ struct nk_image header;
+ struct nk_image window;
+ struct nk_image scrollbar_inc_button;
+ struct nk_image scrollbar_inc_button_hover;
+ struct nk_image scrollbar_dec_button;
+ struct nk_image scrollbar_dec_button_hover;
+ struct nk_image button;
+ struct nk_image button_hover;
+ struct nk_image button_active;
+ struct nk_image tab_minimize;
+ struct nk_image tab_maximize;
+ struct nk_image slider;
+ struct nk_image slider_hover;
+ struct nk_image slider_active;
+};
+
+
+/* ===============================================================
+ *
+ * DEVICE
+ *
+ * ===============================================================*/
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs("\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+static GLuint
+image_load(const char *filename)
+{
+ int x,y,n;
+ GLuint tex;
+ unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+ if (!data) die("failed to load image: %s", filename);
+
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ return tex;
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.null = dev->null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+ nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+ nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
+/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
+static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
+static void text_input(GLFWwindow *win, unsigned int codepoint)
+{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
+static void scroll_input(GLFWwindow *win, double _, double yoff)
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+
+int main(int argc, char *argv[])
+{
+ /* Platform */
+ static GLFWwindow *win;
+ int width = 0, height = 0;
+ int display_width=0, display_height=0;
+
+ /* GUI */
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct media media;
+ struct nk_context ctx;
+ struct nk_font *font;
+
+ /* GLFW */
+ glfwSetErrorCallback(error_callback);
+ if (!glfwInit()) {
+ fprintf(stdout, "[GFLW] failed to init!\n");
+ exit(1);
+ }
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+ win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
+ glfwMakeContextCurrent(win);
+ glfwSetWindowUserPointer(win, &ctx);
+ glfwSetCharCallback(win, text_input);
+ glfwSetScrollCallback(win, scroll_input);
+ glfwGetWindowSize(win, &width, &height);
+ glfwGetFramebufferSize(win, &display_width, &display_height);
+
+ /* OpenGL */
+ glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+ glewExperimental = 1;
+ if (glewInit() != GLEW_OK) {
+ fprintf(stderr, "Failed to setup GLEW\n");
+ exit(1);
+ }
+
+ /* GUI */