Added D3D12 backend and demo

This commit is contained in:
Ludwig Füchsl 2022-02-14 20:51:28 +01:00
parent 3e834293ad
commit 703d73aebf
6 changed files with 1686 additions and 0 deletions

9
demo/d3d12/build.bat Normal file
View File

@ -0,0 +1,9 @@
@echo off
rem This will use VS2015 for compiler... if you have vs 2015 and it is installed at this / the default path
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
fxc.exe /nologo /T vs_5_1 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d12_vertex_shader.h /Vn nk_d3d12_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d12.hlsl
fxc.exe /nologo /T ps_5_1 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d12_pixel_shader.h /Vn nk_d3d12_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv /enable_unbounded_descriptor_tables nuklear_d3d12.hlsl
cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib dxgi.lib d3d12.lib /link /incremental:no

439
demo/d3d12/main.c Normal file
View File

@ -0,0 +1,439 @@
/* nuklear - 1.32.0 - public domain */
#define COBJMACROS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <combaseapi.h>
#include <dxgi1_6.h>
#include <d3d12.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define USER_TEXTURES 6
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_INDEX_BUFFER 128 * 1024
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_D3D12_IMPLEMENTATION
#include "../../nuklear.h"
#include "nuklear_d3d12.h"
/* ===============================================================
*
* EXAMPLE
*
* ===============================================================*/
/* This are some code examples to provide a small overview of what can be
* done with this library. To try out an example uncomment the defines */
/*#define INCLUDE_ALL */
/*#define INCLUDE_STYLE */
/*#define INCLUDE_CALCULATOR */
/*#define INCLUDE_CANVAS */
/*#define INCLUDE_OVERVIEW */
/*#define INCLUDE_NODE_EDITOR */
#ifdef INCLUDE_ALL
#define INCLUDE_STYLE
#define INCLUDE_CALCULATOR
#define INCLUDE_CANVAS
#define INCLUDE_OVERVIEW
#define INCLUDE_NODE_EDITOR
#endif
#ifdef INCLUDE_STYLE
#include "../style.c"
#endif
#ifdef INCLUDE_CALCULATOR
#include "../calculator.c"
#endif
#ifdef INCLUDE_CANVAS
#include "../canvas.c"
#endif
#ifdef INCLUDE_OVERVIEW
#include "../overview.c"
#endif
#ifdef INCLUDE_NODE_EDITOR
#include "../node_editor.c"
#endif
/* ===============================================================
*
* DEMO
*
* ===============================================================*/
/* DXGI & Window related device objects */
static IDXGIFactory2 *dxgi_factory;
static IDXGISwapChain1 *swap_chain;
static ID3D12DescriptorHeap *rtv_descriptor_heap;
static D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[2];
static ID3D12Resource *rtv_buffers[2];
static UINT rtv_desc_increment;
static UINT rtv_index;
/* DirectX common device objects */
static ID3D12Device *device;
static ID3D12CommandQueue *command_queue;
static ID3D12Fence *queue_fence;
static UINT64 fence_value;
static ID3D12CommandAllocator *command_allocator;
static ID3D12GraphicsCommandList *command_list;
static void signal_and_wait()
{
HRESULT hr;
/* Signal fence when execution finishes */
hr = ID3D12CommandQueue_Signal(command_queue, queue_fence, ++fence_value);
assert(SUCCEEDED(hr));
/* Wait for queue to finish */
while(ID3D12Fence_GetCompletedValue(queue_fence) != fence_value)
{
SwitchToThread(); /* Allow windows to do other work */
}
}
static void execute_commands()
{
/* Prepare command list for execution */
ID3D12GraphicsCommandList_Close(command_list);
/* Execute on command queue */
ID3D12CommandList* cmd_lists[] = { (ID3D12CommandList*)command_list};
ID3D12CommandQueue_ExecuteCommandLists(command_queue, 1, cmd_lists);
/* Wait for execution */
signal_and_wait();
/* Reset command allocator and list */
ID3D12CommandAllocator_Reset(command_allocator);
ID3D12GraphicsCommandList_Reset(command_list, command_allocator, NULL);
}
static void get_swap_chain_buffers()
{
HRESULT hr;
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_handle;
/* Get resource objects from swap chain */
hr = IDXGISwapChain1_GetBuffer(swap_chain, 0, &IID_ID3D12Resource, &rtv_buffers[0]);
assert(SUCCEEDED(hr));
hr = IDXGISwapChain1_GetBuffer(swap_chain, 1, &IID_ID3D12Resource, &rtv_buffers[1]);
assert(SUCCEEDED(hr));
/* Recreate render target views */
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_descriptor_heap, &descriptor_handle);
ID3D12Device_CreateRenderTargetView(device, rtv_buffers[0], NULL, descriptor_handle);
rtv_handles[0] = descriptor_handle;
descriptor_handle.ptr += rtv_desc_increment;
ID3D12Device_CreateRenderTargetView(device, rtv_buffers[1], NULL, descriptor_handle);
rtv_handles[1] = descriptor_handle;
}
static void
set_swap_chain_size(int width, int height)
{
HRESULT hr;
/* Wait for pending work */
signal_and_wait();
signal_and_wait(); /* Two times because we have two buffers in flight */
/* Release all open refereces to the buffers */
ID3D12Resource_Release(rtv_buffers[0]);
ID3D12Resource_Release(rtv_buffers[1]);
/* DXGI can now perform resizing */
hr = IDXGISwapChain1_ResizeBuffers(swap_chain, 2, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
assert(SUCCEEDED(hr));
/* Get references for the new resized buffers */
get_swap_chain_buffers();
/* Reset RTV index */
rtv_index = 0;
}
static LRESULT CALLBACK
WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SIZE:
if (swap_chain)
{
int width = LOWORD(lparam);
int height = HIWORD(lparam);
set_swap_chain_size(width, height);
nk_d3d12_resize(width, height);
}
break;
}
if (nk_d3d12_handle_event(wnd, msg, wparam, lparam))
return 0;
return DefWindowProcW(wnd, msg, wparam, lparam);
}
int main(void)
{
struct nk_context *ctx;
struct nk_colorf bg;
WNDCLASSW wc;
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
DWORD style = WS_OVERLAPPEDWINDOW;
DWORD exstyle = WS_EX_APPWINDOW;
HWND wnd;
int running = 1;
HRESULT hr;
D3D12_COMMAND_QUEUE_DESC command_queue_desc;
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
D3D12_DESCRIPTOR_HEAP_DESC rtv_desc_heap_desc;
/* Win32 */
memset(&wc, 0, sizeof(wc));
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandleW(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"NuklearWindowClass";
RegisterClassW(&wc);
AdjustWindowRectEx(&rect, style, FALSE, exstyle);
wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, wc.hInstance, NULL);
/* D3D12 setup */
/* Create default Device */
hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &device);
assert(SUCCEEDED(hr));
/* Create a command queue */
command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
command_queue_desc.NodeMask = 0;
hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc, &IID_ID3D12CommandQueue, &command_queue);
assert(SUCCEEDED(hr));
/* Create a fence for command queue executions */
fence_value = 0;
hr = ID3D12Device_CreateFence(device, fence_value, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, &queue_fence);
assert(SUCCEEDED(hr));
/* Create a command allocator */
hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, &command_allocator);
assert(SUCCEEDED(hr));
/* Create a command list that will use our allocator */
hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator, NULL, &IID_ID3D12GraphicsCommandList1, &command_list);
assert(SUCCEEDED(hr));
/* DXGI Setup (Swap chain & resources) */
/* Create a descriptor heap for the back buffers */
rtv_desc_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_desc_heap_desc.NumDescriptors = 2;
rtv_desc_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
rtv_desc_heap_desc.NodeMask = 0;
hr = ID3D12Device_CreateDescriptorHeap(device, &rtv_desc_heap_desc, &IID_ID3D12DescriptorHeap, &rtv_descriptor_heap);
assert(SUCCEEDED(hr));
/* Get descriptor increment */
rtv_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
/* Get the DXGI factory */
hr = CreateDXGIFactory1(&IID_IDXGIFactory2, &dxgi_factory);
assert(SUCCEEDED(hr));
/* Create the swap chain */
swap_chain_desc.Width = WINDOW_WIDTH;
swap_chain_desc.Height = WINDOW_HEIGHT;
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.Stereo = 0;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.BufferCount = 2;
swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ;
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgi_factory, (IUnknown*)command_queue, wnd, &swap_chain_desc, NULL, NULL, &swap_chain);
assert(SUCCEEDED(hr));
get_swap_chain_buffers();
/* GUI */
ctx = nk_d3d12_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER, USER_TEXTURES);
/* 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_d3d12_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_d3d12_font_stash_end(command_list);
/*nk_style_load_all_cursors(ctx, atlas->cursors);*/
/*nk_style_set_font(ctx, &droid->handle)*/;
}
/* Execute the command list to make sure all texture (font) data has been uploaded */
execute_commands();
/* Now we can cleanup all resources consumed by font stashing that are no longer used */
nk_d3d12_font_stash_cleanup();
/* style.c */
#ifdef INCLUDE_STYLE
/*set_style(ctx, THEME_WHITE);*/
/*set_style(ctx, THEME_RED);*/
/*set_style(ctx, THEME_BLUE);*/
/*set_style(ctx, THEME_DARK);*/
#endif
bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
while (running)
{
/* Input */
MSG msg;
nk_input_begin(ctx);
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
running = 0;
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
nk_input_end(ctx);
/* GUI */
if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button"))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 22, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
nk_layout_row_dynamic(ctx, 120, 1);
bg = nk_color_picker(ctx, bg, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
nk_combo_end(ctx);
}
}
nk_end(ctx);
/* -------------- EXAMPLES ---------------- */
#ifdef INCLUDE_CALCULATOR
calculator(ctx);
#endif
#ifdef INCLUDE_CANVAS
canvas(ctx);
#endif
#ifdef INCLUDE_OVERVIEW
overview(ctx);
#endif
#ifdef INCLUDE_NODE_EDITOR
node_editor(ctx);
#endif
/* ----------------------------------------- */
/* Set rtv resource state */
D3D12_RESOURCE_BARRIER resource_barrier;
resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barrier.Transition.pResource = rtv_buffers[rtv_index];
resource_barrier.Transition.Subresource = 0;
resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
/* Clear and set the rtv */
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_handles[rtv_index], &bg.r, 0, NULL);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handles[rtv_index], FALSE, NULL);
/* Draw */
nk_d3d12_render(command_list, NK_ANTI_ALIASING_ON);
/* Bring the rtv resource back to present state */
resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barrier.Transition.pResource = rtv_buffers[rtv_index];
resource_barrier.Transition.Subresource = 0;
resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
/* Execute command list and wait */
execute_commands();
/* Present frame */
hr = IDXGISwapChain2_Present(swap_chain, 1, 0);
rtv_index = (rtv_index + 1) % 2;
if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {
/* to recover from this, you'll need to recreate device and all the resources */
MessageBoxW(NULL, L"D3D12 device is lost or removed!", L"Error", 0);
break;
} else if (hr == DXGI_STATUS_OCCLUDED) {
/* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
Sleep(10);
}
assert(SUCCEEDED(hr));
}
/* Nuklear shutdown */
nk_d3d12_shutdown();
/* D3D12 and DXGI shutdown */
signal_and_wait();
signal_and_wait(); /* Two times because we have two buffers in flight */
ID3D12Resource_Release(rtv_buffers[0]);
ID3D12Resource_Release(rtv_buffers[1]);
ID3D12DescriptorHeap_Release(rtv_descriptor_heap);
IDXGISwapChain1_Release(swap_chain);
IDXGIFactory2_Release(dxgi_factory);
ID3D12GraphicsCommandList_Release(command_list);
ID3D12CommandAllocator_Release(command_allocator);
ID3D12CommandQueue_Release(command_queue);
ID3D12Fence_Release(queue_fence);
ID3D12Device_Release(device);
/* win32 shutdown */
UnregisterClassW(wc.lpszClassName, wc.hInstance);
return 0;
}

882
demo/d3d12/nuklear_d3d12.h Normal file
View File

@ -0,0 +1,882 @@
/*
* Nuklear - 1.32.0 - public domain
* no warrenty implied; use at your own risk.
* authored from 2015-2016 by Micha Mettke
*
* D3D12 backend created by Ludwig Fuechsl (2022)
*/
/*
* ==============================================================
*
* API
*
* ===============================================================
*/
#ifndef NK_D3D12_H_
#define NK_D3D12_H_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
NK_API struct nk_context *nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures);
NK_API void nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list);
NK_API void nk_d3d12_font_stash_cleanup();
NK_API nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out);
NK_API int nk_d3d12_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
NK_API void nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA);
NK_API void nk_d3d12_resize(int width, int height);
NK_API void nk_d3d12_shutdown(void);
#endif
/*
* ==============================================================
*
* IMPLEMENTATION
*
* ===============================================================
*/
#ifdef NK_D3D12_IMPLEMENTATION
#define WIN32_LEAN_AND_MEAN
#define COBJMACROS
#include <d3d12.h>
#include <stddef.h>
#include <string.h>
#include <float.h>
#include <assert.h>
#include "nuklear_d3d12_vertex_shader.h"
#include "nuklear_d3d12_pixel_shader.h"
struct nk_d3d12_vertex
{
float position[2];
float uv[2];
nk_byte col[4];
};
static struct
{
struct nk_context ctx;
struct nk_font_atlas atlas;
struct nk_buffer cmds;
struct nk_draw_null_texture null;
unsigned int max_vertex_buffer;
unsigned int max_index_buffer;
unsigned int max_user_textures;
D3D12_HEAP_PROPERTIES heap_prop_default;
D3D12_HEAP_PROPERTIES heap_prop_upload;
UINT cbv_srv_uav_desc_increment;
D3D12_VIEWPORT viewport;
ID3D12Device *device;
ID3D12RootSignature *root_signature;
ID3D12PipelineState *pipeline_state;
ID3D12DescriptorHeap *desc_heap;
ID3D12Resource *font_texture;
ID3D12Resource *font_upload_buffer;
ID3D12Resource *upload_buffer;
ID3D12Resource *const_buffer;
ID3D12Resource *index_buffer;
ID3D12Resource *vertex_buffer;
D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle;
D3D12_GPU_VIRTUAL_ADDRESS gpu_vertex_buffer_address;
D3D12_GPU_VIRTUAL_ADDRESS gpu_index_buffer_address;
} d3d12;
NK_API void
nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA)
{
HRESULT hr;
#ifdef NK_UINT_DRAW_INDEX
DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R32_UINT;
#else
DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R16_UINT;
#endif
const UINT stride = sizeof(struct nk_d3d12_vertex);
const struct nk_draw_command *cmd;
UINT offset = 0;
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
unsigned char* ptr_data;
D3D12_RANGE map_range;
D3D12_RESOURCE_BARRIER resource_barriers[3];
/* Activate D3D12 pipeline state and config root signature */
ID3D12GraphicsCommandList_SetPipelineState(command_list, d3d12.pipeline_state);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, d3d12.root_signature);
ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &d3d12.desc_heap);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, d3d12.gpu_descriptor_handle);
/* Configure rendering pipeline */
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
vertex_buffer_view.BufferLocation = d3d12.gpu_vertex_buffer_address;
vertex_buffer_view.SizeInBytes = d3d12.max_vertex_buffer;
vertex_buffer_view.StrideInBytes = stride;
ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vertex_buffer_view);
index_buffer_view.BufferLocation = d3d12.gpu_index_buffer_address;
index_buffer_view.Format = index_buffer_format;
index_buffer_view.SizeInBytes = d3d12.max_index_buffer;
ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &index_buffer_view);
ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &d3d12.viewport);
/* Map upload buffer to cpu accessible pointer */
map_range.Begin = sizeof(float) * 4 * 4;
map_range.End = map_range.Begin + d3d12.max_vertex_buffer + d3d12.max_index_buffer;
hr = ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data);
NK_ASSERT(SUCCEEDED(hr));
/* Nuklear convert and copy to upload buffer */
{
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_d3d12_vertex, position)},
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, uv)},
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d12_vertex, col)},
{NK_VERTEX_LAYOUT_END}
};
memset(&config, 0, sizeof(config));
config.vertex_layout = vertex_layout;
config.vertex_size = sizeof(struct nk_d3d12_vertex);
config.vertex_alignment = NK_ALIGNOF(struct nk_d3d12_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 = d3d12.null;
struct nk_buffer vbuf, ibuf;
nk_buffer_init_fixed(&vbuf, &ptr_data[sizeof(float) * 4 * 4], (size_t)d3d12.max_vertex_buffer);
nk_buffer_init_fixed(&ibuf, &ptr_data[sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer], (size_t)d3d12.max_index_buffer);
nk_convert(&d3d12.ctx, &d3d12.cmds, &vbuf, &ibuf, &config);
}
/* Close mapping range */
ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
/* Issue GPU resource change for copying */
resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[0].Transition.pResource = d3d12.const_buffer;
resource_barriers[0].Transition.Subresource = 0;
resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
resource_barriers[1].Transition.Subresource = 0;
resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[2].Transition.pResource = d3d12.index_buffer;
resource_barriers[2].Transition.Subresource = 0;
resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_INDEX_BUFFER;
resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
/* Copy from upload buffer to gpu buffers */
ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.const_buffer, 0, d3d12.upload_buffer, 0, sizeof(float) * 4 * 4);
ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.vertex_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4, d3d12.max_vertex_buffer);
ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.index_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer, d3d12.max_index_buffer);
/* Issue GPU resource change for rendering */
resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[0].Transition.pResource = d3d12.const_buffer;
resource_barriers[0].Transition.Subresource = 0;
resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
resource_barriers[1].Transition.Subresource = 0;
resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barriers[2].Transition.pResource = d3d12.index_buffer;
resource_barriers[2].Transition.Subresource = 0;
resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
/* Issue draw commands */
nk_draw_foreach(cmd, &d3d12.ctx, &d3d12.cmds)
{
D3D12_RECT scissor;
UINT32 texture_id;
/* Only place a drawcall in case the command contains drawable data */
if(cmd->elem_count)
{
/* Setup scissor rect */
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);
ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &scissor);
/* Setup texture (index to descriptor heap table) to use for draw call */
texture_id = (UINT32)cmd->texture.id;
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &texture_id, 0);
/* Dispatch draw call */
ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, (UINT)cmd->elem_count, 1, offset, 0, 0);
offset += cmd->elem_count;
}
}
/* Default nuklear context and command buffer clear */
nk_clear(&d3d12.ctx);
nk_buffer_clear(&d3d12.cmds);
}
static void
nk_d3d12_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] =
{
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 1.0f },
};
matrix[0][0] = 2.0f / (R - L);
matrix[1][1] = 2.0f / (T - B);
matrix[3][0] = (R + L) / (L - R);
matrix[3][1] = (T + B) / (B - T);
memcpy(result, matrix, sizeof(matrix));
}
NK_API void
nk_d3d12_resize(int width, int height)
{
D3D12_RANGE map_range;
void* ptr_data;
/* Describe area to be mapped (the upload buffer region where the constant buffer / projection matrix) lives */
map_range.Begin = 0;
map_range.End = sizeof(float) * 4 * 4;
/* Map area to cpu accassible pointer (from upload buffer) */
if (SUCCEEDED(ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data)))
{
/* Compute projection matrix into upload buffer */
nk_d3d12_get_projection_matrix(width, height, (float*)ptr_data);
ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
/* Update internal viewport state to relect resize changes */
d3d12.viewport.Width = (float)width;
d3d12.viewport.Height = (float)height;
}
/*
NOTE:
When mapping and copying succeeds, the data will still be in CPU sided memory
copying to the GPU is done in the nk_d3d12_render function
*/
}
NK_API int
nk_d3d12_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(&d3d12.ctx, NK_KEY_SHIFT, down);
return 1;
case VK_DELETE:
nk_input_key(&d3d12.ctx, NK_KEY_DEL, down);
return 1;
case VK_RETURN:
nk_input_key(&d3d12.ctx, NK_KEY_ENTER, down);
return 1;
case VK_TAB:
nk_input_key(&d3d12.ctx, NK_KEY_TAB, down);
return 1;
case VK_LEFT:
if (ctrl)
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_LEFT, down);
else
nk_input_key(&d3d12.ctx, NK_KEY_LEFT, down);
return 1;
case VK_RIGHT:
if (ctrl)
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else
nk_input_key(&d3d12.ctx, NK_KEY_RIGHT, down);
return 1;
case VK_BACK:
nk_input_key(&d3d12.ctx, NK_KEY_BACKSPACE, down);
return 1;
case VK_HOME:
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_START, down);
nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_START, down);
return 1;
case VK_END:
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_END, down);
nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_END, down);
return 1;
case VK_NEXT:
nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_DOWN, down);
return 1;
case VK_PRIOR:
nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_UP, down);
return 1;
case 'C':
if (ctrl) {
nk_input_key(&d3d12.ctx, NK_KEY_COPY, down);
return 1;
}
break;
case 'V':
if (ctrl) {
nk_input_key(&d3d12.ctx, NK_KEY_PASTE, down);
return 1;
}
break;
case 'X':
if (ctrl) {
nk_input_key(&d3d12.ctx, NK_KEY_CUT, down);
return 1;
}
break;
case 'Z':
if (ctrl) {
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_UNDO, down);
return 1;
}
break;
case 'R':
if (ctrl) {
nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REDO, down);
return 1;
}
break;
}
return 0;
}
case WM_CHAR:
if (wparam >= 32)
{
nk_input_unicode(&d3d12.ctx, (nk_rune)wparam);
return 1;
}
break;
case WM_LBUTTONDOWN:
nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_LBUTTONUP:
nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_RBUTTONDOWN:
nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_RBUTTONUP:
nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_MBUTTONDOWN:
nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_MBUTTONUP:
nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_MOUSEWHEEL:
nk_input_scroll(&d3d12.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
return 1;
case WM_MOUSEMOVE:
nk_input_motion(&d3d12.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
return 1;
case WM_LBUTTONDBLCLK:
nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
return 1;
}
return 0;
}
static void
nk_d3d12_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
{
(void)usr;
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
{
HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
if (mem)
{
SIZE_T size = GlobalSize(mem) - 1;
if (size)
{
LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
if (wstr)
{
int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
if (utf8size)
{
char* utf8 = (char*)malloc(utf8size);
if (utf8)
{
WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
nk_textedit_paste(edit, utf8, utf8size);
free(utf8);
}
}
GlobalUnlock(mem);
}
}
}
CloseClipboard();
}
}
static void
nk_d3d12_clipboard_copy(nk_handle usr, const char *text, int len)
{
(void)usr;
if (OpenClipboard(NULL))
{
int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
if (wsize)
{
HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
if (mem)
{
wchar_t* wstr = (wchar_t*)GlobalLock(mem);
if (wstr)
{
MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
wstr[wsize] = 0;
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
}
}
}
CloseClipboard();
}
}
NK_API struct nk_context*
nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures)
{
HRESULT hr;
D3D12_CONSTANT_BUFFER_VIEW_DESC cbv;
D3D12_CPU_DESCRIPTOR_HANDLE cbv_handle;
/* Do plain object / ref copys */
d3d12.max_vertex_buffer = max_vertex_buffer;
d3d12.max_index_buffer = max_index_buffer;
d3d12.max_user_textures = max_user_textures;
d3d12.device = device;
ID3D12Device_AddRef(device);
d3d12.font_texture = NULL;
d3d12.font_upload_buffer = NULL;
/* Init nuklear context */
nk_init_default(&d3d12.ctx, 0);
d3d12.ctx.clip.copy = nk_d3d12_clipboard_copy;
d3d12.ctx.clip.paste = nk_d3d12_clipboard_paste;
d3d12.ctx.clip.userdata = nk_handle_ptr(0);
/* Init nuklear buffer */
nk_buffer_init_default(&d3d12.cmds);
/* Define Heap properties */
d3d12.heap_prop_default.Type = D3D12_HEAP_TYPE_DEFAULT;
d3d12.heap_prop_default.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
d3d12.heap_prop_default.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
d3d12.heap_prop_default.CreationNodeMask = 0;
d3d12.heap_prop_default.VisibleNodeMask = 0;
d3d12.heap_prop_upload.Type = D3D12_HEAP_TYPE_UPLOAD;
d3d12.heap_prop_upload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
d3d12.heap_prop_upload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
d3d12.heap_prop_upload.CreationNodeMask = 0;
d3d12.heap_prop_upload.VisibleNodeMask = 0;
/* Create data objects */
/* Create upload buffer */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = (sizeof(float) * 4 * 4) + max_vertex_buffer + max_index_buffer; /* Needs to hold matrix + vertices + indicies */
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, &d3d12.upload_buffer);
NK_ASSERT(SUCCEEDED(hr));
}
/* Create constant buffer */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = 256; /* Should be sizeof(float) * 4 * 4 - but this does not match how d3d12 works (min CBV size of 256) */
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.const_buffer);
NK_ASSERT(SUCCEEDED(hr));
}
/* Create vertex buffer */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = max_vertex_buffer;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.vertex_buffer);
NK_ASSERT(SUCCEEDED(hr));
}
/* Create index buffer */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = max_index_buffer;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.index_buffer);
NK_ASSERT(SUCCEEDED(hr));
}
/* Create descriptor heap for shader root signature */
{
D3D12_DESCRIPTOR_HEAP_DESC desc;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.NumDescriptors = 2 + max_user_textures;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
desc.NodeMask = 0;
ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, &d3d12.desc_heap);
}
/* Get address of first handle (CPU and GPU) */
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.cpu_descriptor_handle);
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.gpu_descriptor_handle);
/* Get addresses of vertex & index buffers */
d3d12.gpu_vertex_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.vertex_buffer);
d3d12.gpu_index_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.index_buffer);
/* Get handle increment */
d3d12.cbv_srv_uav_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
/* Create view to constant buffer */
cbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(d3d12.const_buffer);
cbv.SizeInBytes = 256;
cbv_handle = d3d12.cpu_descriptor_handle;
ID3D12Device_CreateConstantBufferView(device, &cbv, cbv_handle);
/* Create root signature */
hr = ID3D12Device_CreateRootSignature(device, 0, nk_d3d12_vertex_shader, sizeof(nk_d3d12_vertex_shader), &IID_ID3D12RootSignature, &d3d12.root_signature);
NK_ASSERT(SUCCEEDED(hr));
/* Create pipeline state */
{
/* Describe input layout */
const D3D12_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, position), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NK_OFFSETOF(struct nk_d3d12_vertex, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
/* Describe pipeline state */
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.pRootSignature = d3d12.root_signature;
desc.VS.pShaderBytecode = nk_d3d12_vertex_shader;
desc.VS.BytecodeLength = sizeof(nk_d3d12_vertex_shader);
desc.PS.pShaderBytecode = nk_d3d12_pixel_shader;
desc.PS.BytecodeLength = sizeof(nk_d3d12_pixel_shader);
desc.BlendState.RenderTarget[0].BlendEnable = TRUE;
desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
desc.SampleMask = UINT_MAX;
desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
desc.RasterizerState.CullMode= D3D12_CULL_MODE_NONE;
desc.RasterizerState.DepthClipEnable = TRUE;
desc.InputLayout.NumElements = _countof(layout);
desc.InputLayout.pInputElementDescs = layout;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
desc.NumRenderTargets = 1;
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; /* NOTE: When using HDR rendering you might have a different framebuffer format */
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.NodeMask = 0;
/* Create PSO */
hr = ID3D12Device_CreateGraphicsPipelineState(device, &desc, &IID_ID3D12PipelineState, &d3d12.pipeline_state);
NK_ASSERT(SUCCEEDED(hr));
}
/* First time const buffer init */
nk_d3d12_resize(width, height);
/* viewport */
d3d12.viewport.TopLeftX = 0.0f;
d3d12.viewport.TopLeftY = 0.0f;
d3d12.viewport.Width = (float)width;
d3d12.viewport.Height = (float)height;
d3d12.viewport.MinDepth = 0.0f;
d3d12.viewport.MaxDepth = 1.0f;
return &d3d12.ctx;
}
NK_API void
nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas)
{
/* Default nuklear font stash */
nk_font_atlas_init_default(&d3d12.atlas);
nk_font_atlas_begin(&d3d12.atlas);
*atlas = &d3d12.atlas;
}
NK_API void
nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list)
{
HRESULT hr;
D3D12_TEXTURE_COPY_LOCATION cpy_src, cpy_dest;
D3D12_BOX cpy_box;
D3D12_RESOURCE_BARRIER resource_barrier;
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
const void *image;
void* ptr_data;
int w, h;
/* Bake nuklear font atlas */
image = nk_font_atlas_bake(&d3d12.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
NK_ASSERT(image);
/* Create font texture */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = w;
desc.Height = h;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, &d3d12.font_texture);
NK_ASSERT(SUCCEEDED(hr));
}
/* Create font upload buffer */
{
D3D12_RESOURCE_DESC desc;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = w * h * 4;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, &d3d12.font_upload_buffer);
NK_ASSERT(SUCCEEDED(hr));
}
/* Copy image data to upload buffer */
hr = ID3D12Resource_Map(d3d12.font_upload_buffer, 0, NULL, &ptr_data);
NK_ASSERT(SUCCEEDED(hr));
memcpy(ptr_data, image, w * h * 4);
ID3D12Resource_Unmap(d3d12.font_upload_buffer, 0, NULL);
/* Execute copy operation */
cpy_src.pResource = d3d12.font_upload_buffer;
cpy_src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
cpy_src.PlacedFootprint.Offset = 0;
cpy_src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
cpy_src.PlacedFootprint.Footprint.Width = w;
cpy_src.PlacedFootprint.Footprint.Height = h;
cpy_src.PlacedFootprint.Footprint.Depth = 1;
cpy_src.PlacedFootprint.Footprint.RowPitch = w * 4;
cpy_dest.pResource = d3d12.font_texture;
cpy_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
cpy_dest.SubresourceIndex = 0;
cpy_box.top = 0;
cpy_box.left = 0;
cpy_box.back = 1;
cpy_box.bottom = h;
cpy_box.right = w;
cpy_box.front = 0;
ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &cpy_dest, 0, 0, 0, &cpy_src, &cpy_box);
/* Bring texture in the right state for rendering */
resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resource_barrier.Transition.pResource = d3d12.font_texture;
resource_barrier.Transition.Subresource = 0;
resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
/* Create the SRV for the font texture */
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srv_desc.Texture2D.MipLevels = 1;
srv_desc.Texture2D.MostDetailedMip = 0;
srv_desc.Texture2D.PlaneSlice = 0;
srv_desc.Texture2D.ResourceMinLODClamp = 0.0f;
srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + d3d12.cbv_srv_uav_desc_increment;
ID3D12Device_CreateShaderResourceView(d3d12.device, d3d12.font_texture, &srv_desc, srv_handle);
/* Done with nk atlas data. Atlas will be served with texture id 0 */
nk_font_atlas_end(&d3d12.atlas, nk_handle_id(0), &d3d12.null);
/* Setup default font */
if (d3d12.atlas.default_font)
nk_style_set_font(&d3d12.ctx, &d3d12.atlas.default_font->handle);
}
NK_API
void nk_d3d12_font_stash_cleanup()
{
if(d3d12.font_upload_buffer)
{
ID3D12Resource_Release(d3d12.font_upload_buffer);
d3d12.font_upload_buffer = NULL;
}
}
NK_API
nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out)
{
nk_bool result = nk_false;
if(index < d3d12.max_user_textures)
{
D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
/* Get handle to texture (0 - Const Buffer; 1 - Font Texture; 2 - First user texture) */
srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + ((2 + index) * d3d12.cbv_srv_uav_desc_increment);
/* Create SRV */
ID3D12Device_CreateShaderResourceView(d3d12.device, texture, description, srv_handle);
/* Set nk handle (0 - Font Texture; 1 - First user texture) */
*handle_out = nk_handle_id(1 + index);
result = nk_true;
}
return result;
}
NK_API
void nk_d3d12_shutdown(void)
{
/* Nuklear cleanup */
nk_font_atlas_clear(&d3d12.atlas);
nk_buffer_free(&d3d12.cmds);
nk_free(&d3d12.ctx);
/* DirectX 12 cleanup */
ID3D12Device_Release(d3d12.device);
ID3D12PipelineState_Release(d3d12.pipeline_state);
ID3D12RootSignature_Release(d3d12.root_signature);
ID3D12DescriptorHeap_Release(d3d12.desc_heap);
ID3D12Resource_Release(d3d12.upload_buffer);
ID3D12Resource_Release(d3d12.const_buffer);
ID3D12Resource_Release(d3d12.index_buffer);
ID3D12Resource_Release(d3d12.vertex_buffer);
if(d3d12.font_texture)
ID3D12Resource_Release(d3d12.font_texture);
if(d3d12.font_upload_buffer)
ID3D12Resource_Release(d3d12.font_upload_buffer);
}
#endif

View File

@ -0,0 +1,53 @@
#define NK_ROOTSIGNATURE ""\
"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),"\
"DescriptorTable("\
"CBV(b0, numDescriptors = 1, flags = DATA_VOLATILE),"\
"SRV(t0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)"\
"),"\
"RootConstants(num32BitConstants = 1, b1),"\
"StaticSampler(s0, "\
"filter = FILTER_MIN_MAG_MIP_LINEAR,"\
"addressU = TEXTURE_ADDRESS_CLAMP,"\
"addressV = TEXTURE_ADDRESS_CLAMP,"\
"addressW = TEXTURE_ADDRESS_CLAMP,"\
"comparisonFunc = COMPARISON_ALWAYS"\
")"
cbuffer buffer0 : register(b0)
{
float4x4 ProjectionMatrix;
};
static uint texture_index : register(b1);
sampler sampler0 : register(s0);
Texture2D<float4> textures[] : register(t0);
struct VS_INPUT
{
float2 pos : POSITION;
float4 col : COLOR0;
float2 uv : TEXCOORD0;
};
struct PS_INPUT
{
float4 pos : SV_POSITION;
float4 col : COLOR0;
float2 uv : TEXCOORD0;
};
[RootSignature(NK_ROOTSIGNATURE)]
PS_INPUT vs(VS_INPUT input)
{
PS_INPUT output;
output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
output.col = input.col;
output.uv = input.uv;
return output;
}
[RootSignature(NK_ROOTSIGNATURE)]
float4 ps(PS_INPUT input) : SV_Target
{
return input.col * textures[texture_index].Sample(sampler0, input.uv);
}

View File

@ -0,0 +1,135 @@
#if 0
//
// Generated by Microsoft (R) D3D Shader Disassembler
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_POSITION 0 xyzw 0 POS float
// COLOR 0 xyzw 1 NONE float xyzw
// TEXCOORD 0 xy 2 NONE float xy
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_Target 0 xyzw 0 TARGET float xyzw
//
ps_5_1
dcl_globalFlags refactoringAllowed
dcl_sampler S0[0:0], mode_default, space=0
dcl_resource_texture2d (float,float,float,float) T0[0:*], space=0
dcl_input_ps linear v1.xyzw
dcl_input_ps linear v2.xy
dcl_output o0.xyzw
dcl_temps 1
sample r0.xyzw, v2.xyxx, T0[0].xyzw, S0[0]
mul o0.xyzw, r0.xyzw, v1.xyzw
ret
// Approximately 0 instruction slots used
#endif
const BYTE nk_d3d12_pixel_shader[] =
{
68, 88, 66, 67, 228, 128,
250, 93, 94, 248, 174, 160,
102, 133, 107, 228, 84, 49,
109, 253, 1, 0, 0, 0,
72, 2, 0, 0, 4, 0,
0, 0, 48, 0, 0, 0,
164, 0, 0, 0, 216, 0,
0, 0, 152, 1, 0, 0,
73, 83, 71, 78, 108, 0,
0, 0, 3, 0, 0, 0,
8, 0, 0, 0, 80, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 92, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 0,
15, 15, 0, 0, 98, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 2, 0, 0, 0,
3, 3, 0, 0, 83, 86,
95, 80, 79, 83, 73, 84,
73, 79, 78, 0, 67, 79,
76, 79, 82, 0, 84, 69,
88, 67, 79, 79, 82, 68,
0, 171, 79, 83, 71, 78,
44, 0, 0, 0, 1, 0,
0, 0, 8, 0, 0, 0,
32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0,
0, 0, 15, 0, 0, 0,
83, 86, 95, 84, 97, 114,
103, 101, 116, 0, 171, 171,
83, 72, 69, 88, 184, 0,
0, 0, 81, 0, 0, 0,
46, 0, 0, 0, 106, 8,
0, 1, 90, 0, 0, 6,
70, 110, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 88, 24, 0, 7,
70, 126, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0,
255, 255, 255, 255, 85, 85,
0, 0, 0, 0, 0, 0,
98, 16, 0, 3, 242, 16,
16, 0, 1, 0, 0, 0,
98, 16, 0, 3, 50, 16,
16, 0, 2, 0, 0, 0,
101, 0, 0, 3, 242, 32,
16, 0, 0, 0, 0, 0,
104, 0, 0, 2, 1, 0,
0, 0, 69, 0, 0, 11,
242, 0, 16, 0, 0, 0,
0, 0, 70, 16, 16, 0,
2, 0, 0, 0, 70, 126,
32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 96,
32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 56, 0,
0, 7, 242, 32, 16, 0,
0, 0, 0, 0, 70, 14,
16, 0, 0, 0, 0, 0,
70, 30, 16, 0, 1, 0,
0, 0, 62, 0, 0, 1,
82, 84, 83, 48, 168, 0,
0, 0, 2, 0, 0, 0,
2, 0, 0, 0, 24, 0,
0, 0, 1, 0, 0, 0,
116, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 48, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 104, 0,
0, 0, 2, 0, 0, 0,
56, 0, 0, 0, 2, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 2, 0, 0, 0,
255, 255, 255, 255, 0, 0,
0, 0, 255, 255, 255, 255,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
255, 255, 255, 255, 1, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 21, 0,
0, 0, 3, 0, 0, 0,
3, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
16, 0, 0, 0, 8, 0,
0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 255, 255,
127, 127, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0
};

View File

@ -0,0 +1,168 @@
#if 0
//
// Generated by Microsoft (R) D3D Shader Disassembler
//
//
// Input signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// POSITION 0 xy 0 NONE float xy
// COLOR 0 xyzw 1 NONE float xyzw
// TEXCOORD 0 xy 2 NONE float xy
//
//
// Output signature:
//
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_POSITION 0 xyzw 0 POS float xyzw
// COLOR 0 xyzw 1 NONE float xyzw
// TEXCOORD 0 xy 2 NONE float xy
//
vs_5_1
dcl_globalFlags refactoringAllowed
dcl_constantbuffer CB0[0:0][4], immediateIndexed, space=0
dcl_input v0.xy
dcl_input v1.xyzw
dcl_input v2.xy
dcl_output_siv o0.xyzw, position
dcl_output o1.xyzw
dcl_output o2.xy
dcl_temps 1
mul r0.xyzw, v0.yyyy, CB0[0][1].xyzw
mad r0.xyzw, CB0[0][0].xyzw, v0.xxxx, r0.xyzw
add o0.xyzw, r0.xyzw, CB0[0][3].xyzw
mov o1.xyzw, v1.xyzw
mov o2.xy, v2.xyxx
ret
// Approximately 0 instruction slots used
#endif
const BYTE nk_d3d12_vertex_shader[] =
{
68, 88, 66, 67, 187, 129,
163, 57, 169, 94, 219, 158,
174, 23, 30, 91, 108, 150,
135, 141, 1, 0, 0, 0,
232, 2, 0, 0, 4, 0,
0, 0, 48, 0, 0, 0,
160, 0, 0, 0, 20, 1,
0, 0, 56, 2, 0, 0,
73, 83, 71, 78, 104, 0,
0, 0, 3, 0, 0, 0,
8, 0, 0, 0, 80, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 0, 0, 0, 0,
3, 3, 0, 0, 89, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 0,
15, 15, 0, 0, 95, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 2, 0, 0, 0,
3, 3, 0, 0, 80, 79,
83, 73, 84, 73, 79, 78,
0, 67, 79, 76, 79, 82,
0, 84, 69, 88, 67, 79,
79, 82, 68, 0, 79, 83,
71, 78, 108, 0, 0, 0,
3, 0, 0, 0, 8, 0,
0, 0, 80, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 15, 0,
0, 0, 92, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
1, 0, 0, 0, 15, 0,
0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0,
2, 0, 0, 0, 3, 12,
0, 0, 83, 86, 95, 80,
79, 83, 73, 84, 73, 79,
78, 0, 67, 79, 76, 79,
82, 0, 84, 69, 88, 67,
79, 79, 82, 68, 0, 171,
83, 72, 69, 88, 28, 1,
0, 0, 81, 0, 1, 0,
71, 0, 0, 0, 106, 8,
0, 1, 89, 0, 0, 7,
70, 142, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0,
0, 0, 0, 0, 0, 0,
95, 0, 0, 3, 50, 16,
16, 0, 0, 0, 0, 0,
95, 0, 0, 3, 242, 16,
16, 0, 1, 0, 0, 0,
95, 0, 0, 3, 50, 16,
16, 0, 2, 0, 0, 0,
103, 0, 0, 4, 242, 32,
16, 0, 0, 0, 0, 0,
1, 0, 0, 0, 101, 0,
0, 3, 242, 32, 16, 0,
1, 0, 0, 0, 101, 0,
0, 3, 50, 32, 16, 0,
2, 0, 0, 0, 104, 0,
0, 2, 1, 0, 0, 0,
56, 0, 0, 9, 242, 0,
16, 0, 0, 0, 0, 0,
86, 21, 16, 0, 0, 0,
0, 0, 70, 142, 48, 0,
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0,
50, 0, 0, 11, 242, 0,
16, 0, 0, 0, 0, 0,
70, 142, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 16,
16, 0, 0, 0, 0, 0,
70, 14, 16, 0, 0, 0,
0, 0, 0, 0, 0, 9,
242, 32, 16, 0, 0, 0,
0, 0, 70, 14, 16, 0,
0, 0, 0, 0, 70, 142,
48, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0,
0, 0, 54, 0, 0, 5,
242, 32, 16, 0, 1, 0,
0, 0, 70, 30, 16, 0,
1, 0, 0, 0, 54, 0,
0, 5, 50, 32, 16, 0,
2, 0, 0, 0, 70, 16,
16, 0, 2, 0, 0, 0,
62, 0, 0, 1, 82, 84,
83, 48, 168, 0, 0, 0,
2, 0, 0, 0, 2, 0,
0, 0, 24, 0, 0, 0,
1, 0, 0, 0, 116, 0,
0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 48, 0, 0, 0,
1, 0, 0, 0, 0, 0,
0, 0, 104, 0, 0, 0,
2, 0, 0, 0, 56, 0,
0, 0, 2, 0, 0, 0,
1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 255, 255,
255, 255, 0, 0, 0, 0,
255, 255, 255, 255, 0, 0,
0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 255, 255,
255, 255, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0,
0, 0, 21, 0, 0, 0,
3, 0, 0, 0, 3, 0,
0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 16, 0,
0, 0, 8, 0, 0, 0,
2, 0, 0, 0, 0, 0,
0, 0, 255, 255, 127, 127,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
};