aboutsummaryrefslogtreecommitdiff
path: root/nuklear/demo
diff options
context:
space:
mode:
Diffstat (limited to 'nuklear/demo')
-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
37 files changed, 10376 insertions, 0 deletions
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