浏览代码

Converted windows demos into singe header files

vurtun 9 年之前
父节点
当前提交
953cc967bb
共有 9 个文件被更改,包括 2334 次插入2278 次删除
  1. 3 4
      demo/d3d11/main.c
  2. 0 587
      demo/d3d11/nuklear_d3d11.c
  3. 608 2
      demo/d3d11/nuklear_d3d11.h
  4. 3 2
      demo/gdi/main.c
  5. 0 714
      demo/gdi/nuklear_gdi.c
  6. 737 4
      demo/gdi/nuklear_gdi.h
  7. 4 2
      demo/gdip/main.c
  8. 0 958
      demo/gdip/nuklear_gdip.c
  9. 979 5
      demo/gdip/nuklear_gdip.h

+ 3 - 4
demo/d3d11/main.c

@@ -14,17 +14,16 @@
 #define MAX_VERTEX_BUFFER 512 * 1024
 #define MAX_VERTEX_BUFFER 512 * 1024
 #define MAX_INDEX_BUFFER 128 * 1024
 #define MAX_INDEX_BUFFER 128 * 1024
 
 
-/* these defines are both needed for the header
- * and source file. So if you split them remember
- * to copy them as well. */
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
 #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
 #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
 #define NK_INCLUDE_FONT_BAKING
 #define NK_INCLUDE_FONT_BAKING
 #define NK_INCLUDE_DEFAULT_FONT
 #define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D11_IMPLEMENTATION
+#include "../../nuklear.h"
 #include "nuklear_d3d11.h"
 #include "nuklear_d3d11.h"
-#include "nuklear_d3d11.c"
 
 
 /* ===============================================================
 /* ===============================================================
  *
  *

+ 0 - 587
demo/d3d11/nuklear_d3d11.c

@@ -1,587 +0,0 @@
-#define WIN32_LEAN_AND_MEAN
-#define COBJMACROS
-#include <d3d11.h>
-
-#include <stddef.h>
-#include <string.h>
-#include <float.h>
-#include <assert.h>
-
-#define NK_IMPLEMENTATION
-#include "nuklear_d3d11.h"
-#include "../../nuklear.h"
-
-#include "nuklear_d3d11_vertex_shader.h"
-#include "nuklear_d3d11_pixel_shader.h"
-
-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_draw_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);
-        assert(SUCCEEDED(hr));
-
-        hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);
-        assert(SUCCEEDED(hr));
- 
-        {
-            /* fill converting configuration */
-            struct nk_convert_config config;
-            memset(&config, 0, sizeof(config));
-            config.global_alpha = 1.0f;
-            config.shape_AA = AA;
-            config.line_AA = AA;
-            config.circle_segment_count = 22;
-            config.curve_segment_count = 22;
-            config.arc_segment_count = 22;
-            config.null = 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)
-        {
-            ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;
-            D3D11_RECT scissor;
-            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);
-            return 1;
-
-        case VK_END:
-            nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, 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 = 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 = 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);
-        assert(SUCCEEDED(hr));
-    }
-
-    /* vertex shader */
-    {
-        hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);
-        assert(SUCCEEDED(hr));
-    }
-
-    /* input layout */
-    {
-        const D3D11_INPUT_ELEMENT_DESC layout[] =
-        {
-            { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_draw_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },
-            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, offsetof(struct nk_draw_vertex, uv),       D3D11_INPUT_PER_VERTEX_DATA, 0 },
-            { "COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, offsetof(struct nk_draw_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);
-        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);
-        assert(SUCCEEDED(hr));}
-    }
-
-    /* pixel shader */
-    {
-        hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);
-        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);
-        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);
-        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);
-        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);
-        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);
-}

+ 608 - 2
demo/d3d11/nuklear_d3d11.h

@@ -1,7 +1,20 @@
+/*
+ * Nuklear - v1.00 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
 #ifndef NK_D3D11_H_
 #ifndef NK_D3D11_H_
 #define NK_D3D11_H_
 #define NK_D3D11_H_
 
 
-#include "../../nuklear.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
 
 
 typedef struct ID3D11Device ID3D11Device;
 typedef struct ID3D11Device ID3D11Device;
 typedef struct ID3D11DeviceContext ID3D11DeviceContext;
 typedef struct ID3D11DeviceContext ID3D11DeviceContext;
@@ -9,10 +22,603 @@ 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 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_begin(struct nk_font_atlas **atlas);
 NK_API void nk_d3d11_font_stash_end(void);
 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_render(ID3D11DeviceContext *context, enum nk_anti_aliasing);
 NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);
 NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);
 NK_API void nk_d3d11_shutdown(void);
 NK_API void nk_d3d11_shutdown(void);
 
 
-NK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+/*
+ * ==============================================================
+ *
+ *                          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"
+
+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_draw_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);
+        assert(SUCCEEDED(hr));
+
+        hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);
+        assert(SUCCEEDED(hr));
+ 
+        {
+            /* fill converting configuration */
+            struct nk_convert_config config;
+            memset(&config, 0, sizeof(config));
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.null = 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)
+        {
+            ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;
+            D3D11_RECT scissor;
+            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);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, 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 = 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 = 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);
+        assert(SUCCEEDED(hr));
+    }
+
+    /* vertex shader */
+    {
+        hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);
+        assert(SUCCEEDED(hr));
+    }
+
+    /* input layout */
+    {
+        const D3D11_INPUT_ELEMENT_DESC layout[] =
+        {
+            { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_draw_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, offsetof(struct nk_draw_vertex, uv),       D3D11_INPUT_PER_VERTEX_DATA, 0 },
+            { "COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, offsetof(struct nk_draw_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);
+        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);
+        assert(SUCCEEDED(hr));}
+    }
+
+    /* pixel shader */
+    {
+        hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);
+        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);
+        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);
+        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);
+        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);
+        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
 #endif
+

+ 3 - 2
demo/gdi/main.c

@@ -12,8 +12,10 @@
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDI_IMPLEMENTATION
+#include "../../nuklear.h"
 #include "nuklear_gdi.h"
 #include "nuklear_gdi.h"
-#include "nuklear_gdi.c"
 
 
 /* ===============================================================
 /* ===============================================================
  *
  *
@@ -79,7 +81,6 @@ int main(void)
     atom = RegisterClassW(&wc);
     atom = RegisterClassW(&wc);
 
 
     AdjustWindowRectEx(&rect, style, FALSE, exstyle);
     AdjustWindowRectEx(&rect, style, FALSE, exstyle);
-
     wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
     wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
         style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
         style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
         rect.right - rect.left, rect.bottom - rect.top,
         rect.right - rect.left, rect.bottom - rect.top,

+ 0 - 714
demo/gdi/nuklear_gdi.c

@@ -1,714 +0,0 @@
-#include <stdlib.h>
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <malloc.h>
-
-#define NK_IMPLEMENTATION
-#include "nuklear_gdi.h"
-#include "../../nuklear.h"
-
-struct GdiFont {
-    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 = _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 = _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 = 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 = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
-            if (mem)
-            {
-                wchar_t* wstr = 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;
-    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;
-    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);
-            return 1;
-
-        case VK_END:
-            nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, 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);
-}

+ 737 - 4
demo/gdi/nuklear_gdi.h

@@ -1,18 +1,751 @@
+/*
+ * Nuklear - v1.00 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
 #ifndef NK_GDI_H_
 #ifndef NK_GDI_H_
 #define NK_GDI_H_
 #define NK_GDI_H_
 
 
-#include "../../nuklear.h"
-
-typedef struct GdiFont GdiFont;
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
 
 
 NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);
 NK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);
-NK_API void nk_gdi_set_font(GdiFont *font);
 NK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
 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_render(struct nk_color clear);
 NK_API void nk_gdi_shutdown(void);
 NK_API void nk_gdi_shutdown(void);
 
 
 /* font */
 /* font */
+typedef struct GdiFont GdiFont;
 NK_API GdiFont* nk_gdifont_create(const char *name, int size);
 NK_API GdiFont* nk_gdifont_create(const char *name, int size);
 NK_API void nk_gdifont_del(GdiFont *font);
 NK_API void nk_gdifont_del(GdiFont *font);
+NK_API void nk_gdi_set_font(GdiFont *font);
 
 
 #endif
 #endif
+
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_GDI_IMPLEMENTATION
+
+#include <stdlib.h>
+#include <malloc.h>
+
+struct GdiFont {
+    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 = _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 = _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 = 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 = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+            if (mem)
+            {
+                wchar_t* wstr = 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;
+    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;
+    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);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, 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
+

+ 4 - 2
demo/gdip/main.c

@@ -12,15 +12,17 @@
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_STANDARD_IO
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
 #define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_IMPLEMENTATION
+#define NK_GDIP_IMPLEMENTATION
+#include "../../nuklear.h"
 #include "nuklear_gdip.h"
 #include "nuklear_gdip.h"
-#include "nuklear_gdip.c"
 
 
 /* ===============================================================
 /* ===============================================================
  *
  *
  *                          EXAMPLE
  *                          EXAMPLE
  *
  *
  * ===============================================================*/
  * ===============================================================*/
-/* This are some code examples to provide a small overview of what can be
+/* 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
  * done with this library. To try out an example uncomment the include
  * and the corresponding function. */
  * and the corresponding function. */
  #define UNUSED(a) (void)a
  #define UNUSED(a) (void)a

+ 0 - 958
demo/gdip/nuklear_gdip.c

@@ -1,958 +0,0 @@
-#include <stdlib.h>
-#include <malloc.h>
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-#define NK_IMPLEMENTATION
-#include "nuklear_gdip.h"
-#include "../../nuklear.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);
-
-
-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 = _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, (GpFont *)font, &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)
-{
-    GpFont* font;
-    GpFontFamily *family;
-
-    int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
-    WCHAR* wname = _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);
-    GdipDeleteFontFamily(family);
-
-    return (GdipFont *)font;
-}
-
-static float
-nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)
-{
-    GpFont *font = (GpFont *)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 = _alloca(wsize * sizeof(wchar_t));
-    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
-
-    GdipMeasureString(gdip.memory, wstr, wsize, font, &layout, gdip.format, &bbox, NULL, NULL);
-    return bbox.Width;
-}
-
-void
-nk_gdipfont_del(GdipFont *font)
-{
-    if(!font) return;
-    GdipDeleteFont((GpFont *)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 = 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 = 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 = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
-    if (!mem) {
-        CloseClipboard();
-        return;
-    }
-
-    wstr = 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;
-    font.userdata = nk_handle_ptr(gdipfont);
-    GdipGetFontSize((GpFont *)gdipfont, &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);
-            return 1;
-
-        case VK_END:
-            nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, 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);
-}

+ 979 - 5
demo/gdip/nuklear_gdip.h

@@ -1,9 +1,20 @@
-#ifndef NK_GDI_H_
-#define NK_GDI_H_
+/*
+ * Nuklear - v1.00 - 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_
 
 
-#include "../../nuklear.h"
-
-typedef struct GdipFont GdipFont;
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
 
 
 NK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height);
 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 void nk_gdip_set_font(GdipFont *font);
@@ -12,7 +23,970 @@ NK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear);
 NK_API void nk_gdip_shutdown(void);
 NK_API void nk_gdip_shutdown(void);
 
 
 /* font */
 /* font */
+typedef struct GdipFont GdipFont;
 NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
 NK_API GdipFont* nk_gdipfont_create(const char *name, int size);
 NK_API void nk_gdipfont_del(GdipFont *font);
 NK_API void nk_gdipfont_del(GdipFont *font);
 
 
 #endif
 #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);
+
+
+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 = _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, (GpFont *)font, &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)
+{
+    GpFont* font;
+    GpFontFamily *family;
+
+    int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+    WCHAR* wname = _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);
+    GdipDeleteFontFamily(family);
+
+    return (GdipFont *)font;
+}
+
+static float
+nk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)
+{
+    GpFont *font = (GpFont *)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 = _alloca(wsize * sizeof(wchar_t));
+    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+
+    GdipMeasureString(gdip.memory, wstr, wsize, font, &layout, gdip.format, &bbox, NULL, NULL);
+    return bbox.Width;
+}
+
+void
+nk_gdipfont_del(GdipFont *font)
+{
+    if(!font) return;
+    GdipDeleteFont((GpFont *)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 = 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 = 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 = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+    if (!mem) {
+        CloseClipboard();
+        return;
+    }
+
+    wstr = 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;
+    font.userdata = nk_handle_ptr(gdipfont);
+    GdipGetFontSize((GpFont *)gdipfont, &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);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, 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
+