浏览代码

Demo using Direct3D 9 for rendering

Martins Mozeiko 8 年之前
父节点
当前提交
e14dd1cb1b
共有 4 个文件被更改,包括 843 次插入0 次删除
  1. 6 0
      demo/d3d9/build.bat
  2. 298 0
      demo/d3d9/main.c
  3. 533 0
      demo/d3d9/nuklear_d3d9.h
  4. 6 0
      nuklear.h

+ 6 - 0
demo/d3d9/build.bat

@@ -0,0 +1,6 @@
+@echo off
+
+rem This will use VS2015 for compiler
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib d3d9.lib /link /incremental:no

+ 298 - 0
demo/d3d9/main.c

@@ -0,0 +1,298 @@
+/* nuklear - 1.32.0 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d9.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D9_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d9.h"
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #define UNUSED(a) (void)a
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+ #define MAX(a,b) ((a) < (b) ? (b) : (a))
+ #define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+static IDirect3DDevice9 *device;
+static IDirect3DDevice9Ex *deviceEx;
+static D3DPRESENT_PARAMETERS present;
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        return 0;
+
+    case WM_SIZE:
+        if (device)
+        {
+            UINT width = LOWORD(lparam);
+            UINT height = HIWORD(lparam);
+            if (width != 0 && height != 0 &&
+                (width != present.BackBufferWidth || height != present.BackBufferHeight))
+            {
+                nk_d3d9_release();
+                present.BackBufferWidth = width;
+                present.BackBufferHeight = height;
+                HRESULT hr = IDirect3DDevice9_Reset(device, &present);
+                NK_ASSERT(SUCCEEDED(hr));
+                nk_d3d9_resize(width, height);
+            }
+        }
+        break;
+    }
+
+    if (nk_d3d9_handle_event(wnd, msg, wparam, lparam))
+        return 0;
+
+    return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+static void create_d3d9_device(HWND wnd)
+{
+    HRESULT hr;
+
+    present.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+    present.BackBufferWidth = WINDOW_WIDTH;
+    present.BackBufferHeight = WINDOW_HEIGHT;
+    present.BackBufferFormat = D3DFMT_X8R8G8B8;
+    present.BackBufferCount = 1;
+    present.MultiSampleType = D3DMULTISAMPLE_NONE;
+    present.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    present.hDeviceWindow = wnd;
+    present.EnableAutoDepthStencil = TRUE;
+    present.AutoDepthStencilFormat = D3DFMT_D24S8;
+    present.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
+    present.Windowed = TRUE;
+
+    {/* first try to create Direct3D9Ex device if possible (on Windows 7+) */
+        typedef HRESULT WINAPI Direct3DCreate9ExPtr(UINT, IDirect3D9Ex**);
+        Direct3DCreate9ExPtr *Direct3DCreate9Ex = (void *)GetProcAddress(GetModuleHandleA("d3d9.dll"), "Direct3DCreate9Ex");
+        if (Direct3DCreate9Ex) {
+            IDirect3D9Ex *d3d9ex;
+            if (SUCCEEDED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex))) {
+                hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                    D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                    &present, NULL, &deviceEx);
+                if (SUCCEEDED(hr)) {
+                    device = (IDirect3DDevice9 *)deviceEx;
+                } else {
+                    /* hardware vertex processing not supported, no big deal
+                    retry with software vertex processing */
+                    hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                        &present, NULL, &deviceEx);
+                    if (SUCCEEDED(hr)) {
+                        device = (IDirect3DDevice9 *)deviceEx;
+                    }
+                }
+                IDirect3D9Ex_Release(d3d9ex);
+            }
+        }
+    }
+
+    if (!device) {
+        /* otherwise do regular D3D9 setup */
+        IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+
+        hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+            D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+            &present, &device);
+        if (FAILED(hr)) {
+            /* hardware vertex processing not supported, no big deal
+            retry with software vertex processing */
+            hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                &present, &device);
+            NK_ASSERT(SUCCEEDED(hr));
+        }
+        IDirect3D9_Release(d3d9);
+    }
+}
+
+int main(void)
+{
+    struct nk_context *ctx;
+    struct nk_color background;
+
+    WNDCLASSW wc;
+    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+    DWORD style = WS_OVERLAPPEDWINDOW;
+    DWORD exstyle = WS_EX_APPWINDOW;
+    HWND wnd;
+    int running = 1;
+
+    /* Win32 */
+    memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
+    wc.lpfnWndProc = WindowProc;
+    wc.hInstance = GetModuleHandleW(0);
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.lpszClassName = L"NuklearWindowClass";
+    RegisterClassW(&wc);
+
+    AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+        rect.right - rect.left, rect.bottom - rect.top,
+        NULL, NULL, wc.hInstance, NULL);
+
+    create_d3d9_device(wnd);
+
+    /* GUI */
+    ctx = nk_d3d9_init(device, WINDOW_WIDTH, WINDOW_HEIGHT);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    {struct nk_font_atlas *atlas;
+    nk_d3d9_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    nk_d3d9_font_stash_end();
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+    /* style.c */
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+
+    background = nk_rgb(28,48,62);
+    while (running)
+    {
+        /* Input */
+        MSG msg;
+        nk_input_begin(ctx);
+        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+            if (msg.message == WM_QUIT)
+                running = 0;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            nk_layout_row_dynamic(ctx, 20, 1);
+            nk_label(ctx, "background:", NK_TEXT_LEFT);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        /*calculator(ctx);*/
+        /*overview(ctx);*/
+        /*node_editor(ctx);*/
+        /* ----------------------------------------- */
+
+        /* Draw */
+        {
+            HRESULT hr;
+
+            hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
+                D3DCOLOR_ARGB(background.a, background.r, background.g, background.b), 0.0f, 0);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            hr = IDirect3DDevice9_BeginScene(device);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            nk_d3d9_render(NK_ANTI_ALIASING_ON);
+
+            hr = IDirect3DDevice9_EndScene(device);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            if (deviceEx) {
+                hr = IDirect3DDevice9Ex_PresentEx(deviceEx, NULL, NULL, NULL, NULL, 0);
+            } else {
+                hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+            }
+
+            if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG || hr == D3DERR_DEVICEREMOVED) {
+                /* to recover from this, you'll need to recreate device and all the resources */
+                MessageBoxW(NULL, L"D3D9 device is lost or removed!", L"Error", 0);
+                break;
+            } else if (hr == S_PRESENT_OCCLUDED) {
+                /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+                Sleep(10);
+            }
+            NK_ASSERT(SUCCEEDED(hr));
+        }
+    }
+
+    nk_d3d9_shutdown();
+    if (deviceEx) {
+        IDirect3DDevice9Ex_Release(deviceEx);
+    } else {
+        IDirect3DDevice9_Release(device);
+    }
+    UnregisterClassW(wc.lpszClassName, wc.hInstance);
+    return 0;
+}

+ 533 - 0
demo/d3d9/nuklear_d3d9.h

@@ -0,0 +1,533 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D9_H_
+#define NK_D3D9_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct IDirect3DDevice9 IDirect3DDevice9;
+
+NK_API struct nk_context *nk_d3d9_init(IDirect3DDevice9 *device, int width, int height);
+NK_API void nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_d3d9_font_stash_end(void);
+NK_API int nk_d3d9_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_d3d9_render(enum nk_anti_aliasing);
+NK_API void nk_d3d9_release(void);
+NK_API void nk_d3d9_resize(int width, int height);
+NK_API void nk_d3d9_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D9_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d9.h>
+
+#include <stddef.h>
+#include <string.h>
+
+struct nk_d3d9_vertex {
+    /* D3d9 FFP requires three coordinate position, but nuklear writes only 2 elements
+       projection matrix doesn't use z coordinate => so it can be any value.
+       Member order here is important! Do not rearrange them! */
+    float position[3];
+    nk_uchar col[4];
+    float uv[2];
+};
+
+static struct {
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    struct nk_buffer cmds;
+
+    struct nk_draw_null_texture null;
+
+    D3DVIEWPORT9 viewport;
+    D3DMATRIX projection;
+    IDirect3DDevice9 *device;
+    IDirect3DTexture9 *texture;
+    IDirect3DStateBlock9 *state;
+} d3d9;
+
+NK_API void
+nk_d3d9_render(enum nk_anti_aliasing AA)
+{
+    HRESULT hr;
+
+    hr = IDirect3DStateBlock9_Apply(d3d9.state);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* projection matrix */
+    IDirect3DDevice9_SetTransform(d3d9.device, D3DTS_PROJECTION, &d3d9.projection);
+
+    /* viewport */
+    IDirect3DDevice9_SetViewport(d3d9.device, &d3d9.viewport);
+
+    /* convert from command queue into draw list and draw to screen */
+    {
+        struct nk_buffer vbuf, ebuf;
+        const struct nk_draw_command *cmd;
+        const nk_draw_index *offset = NULL;
+        UINT vertex_count;
+
+        /* fill converting configuration */
+        struct nk_convert_config config;
+        NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
+            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, position)},
+            {NK_VERTEX_COLOR,    NK_FORMAT_B8G8R8A8, NK_OFFSETOF(struct nk_d3d9_vertex, col)},
+            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, uv)},
+            {NK_VERTEX_LAYOUT_END}
+        };
+        memset(&config, 0, sizeof(config));
+        config.vertex_layout = vertex_layout;
+        config.vertex_size = sizeof(struct nk_d3d9_vertex);
+        config.vertex_alignment = NK_ALIGNOF(struct nk_d3d9_vertex);
+        config.global_alpha = 1.0f;
+        config.shape_AA = AA;
+        config.line_AA = AA;
+        config.circle_segment_count = 22;
+        config.curve_segment_count = 22;
+        config.arc_segment_count = 22;
+        config.null = d3d9.null;
+
+        /* convert shapes into vertexes */
+        nk_buffer_init_default(&vbuf);
+        nk_buffer_init_default(&ebuf);
+        nk_convert(&d3d9.ctx, &d3d9.cmds, &vbuf, &ebuf, &config);
+
+        /* iterate over and execute each draw command */
+        offset = (const nk_draw_index *)nk_buffer_memory_const(&ebuf);
+        vertex_count = (UINT)vbuf.needed / sizeof(struct nk_d3d9_vertex);
+
+        nk_draw_foreach(cmd, &d3d9.ctx, &d3d9.cmds)
+        {
+            RECT scissor;
+            if (!cmd->elem_count) continue;
+
+            hr = IDirect3DDevice9_SetTexture(d3d9.device, 0, (IDirect3DBaseTexture9 *)cmd->texture.ptr);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            scissor.left = (LONG)cmd->clip_rect.x;
+            scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
+            scissor.top = (LONG)cmd->clip_rect.y;
+            scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
+
+            hr = IDirect3DDevice9_SetScissorRect(d3d9.device, &scissor);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            NK_ASSERT(sizeof(nk_draw_index) == sizeof(NK_UINT16));
+            hr = IDirect3DDevice9_DrawIndexedPrimitiveUP(d3d9.device, D3DPT_TRIANGLELIST,
+                0, vertex_count, cmd->elem_count/3, offset, D3DFMT_INDEX16,
+                nk_buffer_memory_const(&vbuf), sizeof(struct nk_d3d9_vertex));
+            NK_ASSERT(SUCCEEDED(hr));
+            offset += cmd->elem_count;
+        }
+
+        nk_buffer_free(&vbuf);
+        nk_buffer_free(&ebuf);
+    }
+
+    nk_clear(&d3d9.ctx);
+}
+
+static void
+nk_d3d9_get_projection_matrix(int width, int height, float *result)
+{
+    const float L = 0.5f;
+    const float R = (float)width + 0.5f;
+    const float T = 0.5f;
+    const float B = (float)height + 0.5f;
+    float matrix[4][4] = {
+        {    2.0f / (R - L),              0.0f, 0.0f, 0.0f },
+        {              0.0f,    2.0f / (T - B), 0.0f, 0.0f },
+        {              0.0f,              0.0f, 0.0f, 0.0f },
+        { (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f },
+    };
+    memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d9_release(void)
+{
+    IDirect3DTexture9_Release(d3d9.texture);
+    IDirect3DStateBlock9_Release(d3d9.state);
+}
+
+static void
+nk_d3d9_create_font_texture()
+{
+    int w, h, y;
+    const void *image;
+
+    HRESULT hr;
+    D3DLOCKED_RECT locked;
+
+    image = nk_font_atlas_bake(&d3d9.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+
+    hr = IDirect3DDevice9_CreateTexture(d3d9.device, w, h, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9.texture, NULL);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    hr = IDirect3DTexture9_LockRect(d3d9.texture, 0, &locked, NULL, 0);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    for (y = 0; y < h; y++) {
+        void *src = (char *)image + y * w * 4;
+        void *dst = (char *)locked.pBits + y * locked.Pitch;
+        memcpy(dst, src, w * 4);
+    }
+
+    hr = IDirect3DTexture9_UnlockRect(d3d9.texture, 0);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    nk_font_atlas_end(&d3d9.atlas, nk_handle_ptr(d3d9.texture), &d3d9.null);
+}
+
+NK_API void
+nk_d3d9_resize(int width, int height)
+{
+    HRESULT hr;
+
+    if (d3d9.texture) {
+        nk_d3d9_create_font_texture();
+    }
+
+    hr = IDirect3DDevice9_BeginStateBlock(d3d9.device);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* vertex format */
+    IDirect3DDevice9_SetFVF(d3d9.device, D3DFVF_XYZ + D3DFVF_DIFFUSE + D3DFVF_TEX1);
+
+    /* blend state */
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ALPHABLENDENABLE, TRUE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_BLENDOP, D3DBLENDOP_ADD);
+
+    /* render state */
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_LIGHTING, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZENABLE, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZWRITEENABLE, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_CULLMODE, D3DCULL_NONE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SCISSORTESTENABLE, TRUE);
+
+    /* sampler state */
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+
+    /* texture stage state */
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+
+    hr = IDirect3DDevice9_EndStateBlock(d3d9.device, &d3d9.state);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    nk_d3d9_get_projection_matrix(width, height, &d3d9.projection.m[0][0]);
+    d3d9.viewport.Width = width;
+    d3d9.viewport.Height = height;
+}
+
+NK_API int
+nk_d3d9_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_KEYDOWN:
+    case WM_KEYUP:
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+    {
+        int down = !((lparam >> 31) & 1);
+        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+        switch (wparam)
+        {
+        case VK_SHIFT:
+        case VK_LSHIFT:
+        case VK_RSHIFT:
+            nk_input_key(&d3d9.ctx, NK_KEY_SHIFT, down);
+            return 1;
+
+        case VK_DELETE:
+            nk_input_key(&d3d9.ctx, NK_KEY_DEL, down);
+            return 1;
+
+        case VK_RETURN:
+            nk_input_key(&d3d9.ctx, NK_KEY_ENTER, down);
+            return 1;
+
+        case VK_TAB:
+            nk_input_key(&d3d9.ctx, NK_KEY_TAB, down);
+            return 1;
+
+        case VK_LEFT:
+            if (ctrl)
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else
+                nk_input_key(&d3d9.ctx, NK_KEY_LEFT, down);
+            return 1;
+
+        case VK_RIGHT:
+            if (ctrl)
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else
+                nk_input_key(&d3d9.ctx, NK_KEY_RIGHT, down);
+            return 1;
+
+        case VK_BACK:
+            nk_input_key(&d3d9.ctx, NK_KEY_BACKSPACE, down);
+            return 1;
+
+        case VK_HOME:
+            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_START, down);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_END, down);
+            return 1;
+
+        case VK_NEXT:
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_DOWN, down);
+            return 1;
+
+        case VK_PRIOR:
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_UP, down);
+            return 1;
+
+        case 'C':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_COPY, down);
+                return 1;
+            }
+            break;
+
+        case 'V':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_PASTE, down);
+                return 1;
+            }
+            break;
+
+        case 'X':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_CUT, down);
+                return 1;
+            }
+            break;
+
+        case 'Z':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_UNDO, down);
+                return 1;
+            }
+            break;
+
+        case 'R':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REDO, down);
+                return 1;
+            }
+            break;
+        }
+        return 0;
+    }
+
+    case WM_CHAR:
+        if (wparam >= 32)
+        {
+            nk_input_unicode(&d3d9.ctx, (nk_rune)wparam);
+            return 1;
+        }
+        break;
+
+    case WM_LBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_LBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_RBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_RBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_MBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MOUSEWHEEL:
+        nk_input_scroll(&d3d9.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+        return 1;
+
+    case WM_MOUSEMOVE:
+        nk_input_motion(&d3d9.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+        return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+nk_d3d9_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    (void)usr;
+    if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) {
+        return;
+    }
+
+    HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+    if (!mem) {
+        CloseClipboard();
+        return;
+    }
+
+    SIZE_T size = GlobalSize(mem) - 1;
+    if (!size) {
+        CloseClipboard();
+        return;
+    }
+
+    LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+    if (!wstr) {
+        CloseClipboard();
+        return;
+    }
+
+    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), NULL, 0, NULL, NULL);
+    if (utf8size) {
+        char *utf8 = (char *)malloc(utf8size);
+        if (utf8) {
+            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
+            nk_textedit_paste(edit, utf8, utf8size);
+            free(utf8);
+        }
+    }
+
+    GlobalUnlock(mem); 
+    CloseClipboard();
+}
+
+static void
+nk_d3d9_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+    (void)usr;
+    if (!OpenClipboard(NULL)) {
+        return;
+    }
+
+    int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+    if (wsize) {
+        HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+        if (mem) {
+            wchar_t *wstr = (wchar_t*)GlobalLock(mem);
+            if (wstr) {
+                MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+                wstr[wsize] = 0;
+                GlobalUnlock(mem);
+                SetClipboardData(CF_UNICODETEXT, mem); 
+            }
+        }
+    }
+
+    CloseClipboard();
+}
+
+NK_API struct nk_context*
+nk_d3d9_init(IDirect3DDevice9 *device, int width, int height)
+{
+    d3d9.device = device;
+    IDirect3DDevice9_AddRef(device);
+
+    nk_init_default(&d3d9.ctx, 0);
+    d3d9.state = NULL;
+    d3d9.texture = NULL;
+    d3d9.ctx.clip.copy = nk_d3d9_clipboard_copy;
+    d3d9.ctx.clip.paste = nk_d3d9_clipboard_paste;
+    d3d9.ctx.clip.userdata = nk_handle_ptr(0);
+
+    nk_buffer_init_default(&d3d9.cmds);
+
+    /* viewport */
+    d3d9.viewport.X = 0;
+    d3d9.viewport.Y = 0;
+    d3d9.viewport.MinZ = 0.0f;
+    d3d9.viewport.MaxZ = 1.0f;
+
+    nk_d3d9_resize(width, height);
+
+    return &d3d9.ctx;
+}
+
+NK_API void
+nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&d3d9.atlas);
+    nk_font_atlas_begin(&d3d9.atlas);
+    *atlas = &d3d9.atlas;
+}
+
+NK_API void
+nk_d3d9_font_stash_end(void)
+{
+    nk_d3d9_create_font_texture();
+
+    if (d3d9.atlas.default_font)
+        nk_style_set_font(&d3d9.ctx, &d3d9.atlas.default_font->handle);
+}
+
+NK_API
+void nk_d3d9_shutdown(void)
+{
+    nk_d3d9_release();
+
+    nk_font_atlas_clear(&d3d9.atlas);
+    nk_buffer_free(&d3d9.cmds);
+    nk_free(&d3d9.ctx);
+}
+
+#endif

+ 6 - 0
nuklear.h

@@ -3137,6 +3137,7 @@ NK_FORMAT_COLOR_BEGIN,
     NK_FORMAT_R32G32B32,
     NK_FORMAT_R32G32B32,
 
 
     NK_FORMAT_R8G8B8A8,
     NK_FORMAT_R8G8B8A8,
+    NK_FORMAT_B8G8R8A8,
     NK_FORMAT_R16G15B16A16,
     NK_FORMAT_R16G15B16A16,
     NK_FORMAT_R32G32B32A32,
     NK_FORMAT_R32G32B32A32,
     NK_FORMAT_R32G32B32A32_FLOAT,
     NK_FORMAT_R32G32B32A32_FLOAT,
@@ -7906,6 +7907,11 @@ nk_draw_vertex_color(void *attribute, const float *values,
         struct nk_color col = nk_rgba_fv(values);
         struct nk_color col = nk_rgba_fv(values);
         NK_MEMCPY(attribute, &col.r, sizeof(col));
         NK_MEMCPY(attribute, &col.r, sizeof(col));
     } break;
     } break;
+    case NK_FORMAT_B8G8R8A8: {
+        struct nk_color col = nk_rgba_fv(values);
+        struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a);
+        NK_MEMCPY(attribute, &bgra, sizeof(bgra));
+    } break;
     case NK_FORMAT_R16G15B16: {
     case NK_FORMAT_R16G15B16: {
         nk_ushort col[3];
         nk_ushort col[3];
         col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);
         col[0] = (nk_ushort)NK_CLAMP(NK_USHORT_MIN, values[0] * NK_USHORT_MAX, NK_USHORT_MAX);