#pragma once /* sokol_cimgui.h -- Dear ImGui renderer using cimgui C bindings Do this: #define SOKOL_CIMGUI_IMPL before you include this file in *one* C file to create the implementation. The following defines are used by the implementation to select the platform-specific embedded shader code (these are the same defines as used by sokol_gfx.h and sokol_app.h): SOKOL_GLCORE33 SOKOL_GLES2 SOKOL_GLES3 SOKOL_D3D11 SOKOL_METAL Optionally provide the following configuration defines before including the implementation: SOKOL_CIMGUI_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) Optionally provide the following macros before including the implementation to override defaults: SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) SOKOL_API_DECL - public function declaration prefix (default: extern) SOKOL_API_IMPL - public function implementation prefix (default: -) If sokol_cimgui.h is compiled as a DLL, define the following before including the declaration or implementation: SOKOL_DLL On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. Include the following headers before sokol_imgui.h (both before including the declaration and implementation): sokol_gfx.h sokol_app.h (except SOKOL_CIMGUI_NO_SOKOL_APP) Additionally, include the following headers before including the implementation: cimgui.h FEATURE OVERVIEW: ================= sokol_cimgui.h implements the initialization, rendering and event-handling code for Dear ImGui (https://github.com/ocornut/imgui) on top of sokol_gfx.h and (optionally) sokol_app.h. The sokol_app.h dependency is optional and used for input event handling. If you only use sokol_gfx.h but not sokol_app.h in your application, define SOKOL_CIMGUI_NO_SOKOL_APP before including the implementation of sokol_imgui.h, this will remove any dependency to sokol_app.h, but you must feed input events into Dear ImGui yourself. sokol_cimgui.h is not thread-safe, all calls must be made from the same thread where sokol_gfx.h is running. HOWTO: ====== --- To initialize sokol-cimgui, call: scimgui_setup(const scimgui_desc_t* desc) This will initialize Dear ImGui and create sokol-gfx resources (two buffers for vertices and indices, a font texture and a pipeline- state-object). Use the following scimgui_desc_t members to configure behaviour: int max_vertices The maximum number of vertices used for UI rendering, default is 65536. sokol-imgui will use this to compute the size of the vertex- and index-buffers allocated via sokol_gfx.h sg_pixel_format color_format The color pixel format of the render pass where the UI will be rendered. The default is SG_PIXELFORMAT_RGBA8 sg_pixel_format depth_format The depth-buffer pixel format of the render pass where the UI will be rendered. The default is SG_PIXELFORMAT_DEPTHSTENCIL. int sample_count The MSAA sample-count of the render pass where the UI will be rendered. The default is 1. float dpi_scale DPI scaling factor. Set this to the result of sapp_dpi_scale(). To render in high resolution on a Retina Mac this would typically be 2.0. The default value is 1.0 const char* ini_filename Use this path as igGetIO()->IniFilename. By default this is 0, so that Dear ImGui will not do any filesystem calls. bool no_default_font Set this to true if you don't want to use ImGui's default font. In this case you need to initialize the font yourself after scimgui_setup() is called. --- At the start of a frame, call: scimgui_new_frame(int width, int height, double delta_time) 'width' and 'height' are the dimensions of the rendering surface, passed to igGetIO()->DisplaySize. 'delta_time' is the frame duration passed to igGetIO()->DeltaTime. For example, if you're using sokol_app.h and render to the default framebuffer: scimgui_new_frame(sapp_width(), sapp_height(), delta_time); --- at the end of the frame, before the sg_end_pass() where you want to render the UI, call: scimgui_render() This will first call igRender(), and then render ImGui's draw list through sokol_gfx.h --- if you're using sokol_app.h, from inside the sokol_app.h event callback, call: bool scimgui_handle_event(const sapp_event* ev); The return value is the value of igGetIO()->WantCaptureKeyboard, if this is true, you might want to skip keyboard input handling in your own event handler. --- finally, on application shutdown, call scimgui_shutdown() LICENSE ======= zlib/libpng license Copyright (c) 2018 Andre Weissflog This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #define SOKOL_CIMGUI_INCLUDED (1) #include #include #if !defined(SOKOL_GFX_INCLUDED) #error "Please include sokol_gfx.h before sokol_imgui.h" #endif #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) #error "Please include sokol_app.h before sokol_imgui.h" #endif #ifndef SOKOL_API_DECL #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) #define SOKOL_API_DECL __declspec(dllexport) #elif defined(_WIN32) && defined(SOKOL_DLL) #define SOKOL_API_DECL __declspec(dllimport) #else #define SOKOL_API_DECL extern #endif #endif typedef struct scimgui_desc_t { int max_vertices; sg_pixel_format color_format; sg_pixel_format depth_format; int sample_count; float dpi_scale; const char* ini_filename; bool no_default_font; } scimgui_desc_t; SOKOL_API_DECL void scimgui_setup(const scimgui_desc_t* desc); SOKOL_API_DECL void scimgui_new_frame(int width, int height, double delta_time); SOKOL_API_DECL void scimgui_render(void); #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) SOKOL_API_DECL bool scimgui_handle_event(const sapp_event* ev); #endif SOKOL_API_DECL void scimgui_shutdown(void); /*-- IMPLEMENTATION ----------------------------------------------------------*/ #ifdef SOKOL_CIMGUI_IMPL #define SOKOL_CIMGUI_IMPL_INCLUDED (1) #if !defined(CIMGUI_DEFINE_ENUMS_AND_STRUCTS) #error "Please include cimgui.h before the sokol_cimgui.h implementation" #endif #include /* offsetof */ #include /* memset */ #ifndef SOKOL_API_IMPL #define SOKOL_API_IMPL #endif #ifndef SOKOL_DEBUG #ifndef NDEBUG #define SOKOL_DEBUG (1) #endif #endif #ifndef SOKOL_ASSERT #include #define SOKOL_ASSERT(c) assert(c) #endif #ifndef _SOKOL_PRIVATE #if defined(__GNUC__) #define _SOKOL_PRIVATE __attribute__((unused)) static #else #define _SOKOL_PRIVATE static #endif #endif /* helper macros */ #define _scimgui_def(val, def) (((val) == 0) ? (def) : (val)) #define _scimgui_clear(val) memset(&val, 0, sizeof(val)) typedef struct { ImVec2 disp_size; } _scimgui_vs_params_t; typedef struct { scimgui_desc_t desc; sg_buffer vbuf; sg_buffer ibuf; sg_image img; sg_shader shd; sg_pipeline pip; #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) bool btn_down[SAPP_MAX_MOUSEBUTTONS]; bool btn_up[SAPP_MAX_MOUSEBUTTONS]; #endif } _scimgui_state_t; static _scimgui_state_t _scimgui; /* embedded shader sources */ #if defined(SOKOL_GLCORE33) static const char* _scimgui_vs_src = "#version 330\n" "uniform vec2 disp_size;\n" "in vec2 position;\n" "in vec2 texcoord0;\n" "in vec4 color0;\n" "out vec2 uv;\n" "out vec4 color;\n" "void main() {\n" " gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0);\n" " uv = texcoord0;\n" " color = color0;\n" "}\n"; static const char* _scimgui_fs_src = "#version 330\n" "uniform sampler2D tex;\n" "in vec2 uv;\n" "in vec4 color;\n" "out vec4 frag_color;\n" "void main() {\n" " frag_color = texture(tex, uv) * color;\n" "}\n"; #elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3) static const char* _scimgui_vs_src = "uniform vec2 disp_size;\n" "attribute vec2 position;\n" "attribute vec2 texcoord0;\n" "attribute vec4 color0;\n" "varying vec2 uv;\n" "varying vec4 color;\n" "void main() {\n" " gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, 1.0);\n" " uv = texcoord0;\n" " color = color0;\n" "}\n"; static const char* _scimgui_fs_src = "precision mediump float;\n" "uniform sampler2D tex;\n" "varying vec2 uv;\n" "varying vec4 color;\n" "void main() {\n" " gl_FragColor = texture2D(tex, uv) * color;\n" "}\n"; #elif defined(SOKOL_METAL) static const char* _scimgui_vs_src = "#include \n" "using namespace metal;\n" "struct params_t {\n" " float2 disp_size;\n" "};\n" "struct vs_in {\n" " float2 pos [[attribute(0)]];\n" " float2 uv [[attribute(1)]];\n" " float4 color [[attribute(2)]];\n" "};\n" "struct vs_out {\n" " float4 pos [[position]];\n" " float2 uv;\n" " float4 color;\n" "};\n" "vertex vs_out _main(vs_in in [[stage_in]], constant params_t& params [[buffer(0)]]) {\n" " vs_out out;\n" " out.pos = float4(((in.pos / params.disp_size)-0.5)*float2(2.0,-2.0), 0.5, 1.0);\n" " out.uv = in.uv;\n" " out.color = in.color;\n" " return out;\n" "}\n"; static const char* _scimgui_fs_src = "#include \n" "using namespace metal;\n" "struct fs_in {\n" " float2 uv;\n" " float4 color;\n" "};\n" "fragment float4 _main(fs_in in [[stage_in]], texture2d tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n" " return tex.sample(smp, in.uv) * in.color;\n" "}\n"; #elif defined(SOKOL_D3D11) /* Shader blobs for D3D11, compiled with: fxc.exe /T vs_5_0 /Fh vs.h /Gec /O3 vs.hlsl fxc.exe /T ps_5_0 /Fh fs.h /Gec /O3 fs.hlsl Vertex shader source: cbuffer params { float2 disp_size; }; struct vs_in { float2 pos: POSITION; float2 uv: TEXCOORD0; float4 color: COLOR0; }; struct vs_out { float2 uv: TEXCOORD0; float4 color: COLOR0; float4 pos: SV_Position; }; vs_out main(vs_in inp) { vs_out outp; outp.pos = float4(((inp.pos/disp_size)-0.5)*float2(2.0,-2.0), 0.5, 1.0); outp.uv = inp.uv; outp.color = inp.color; return outp; } Fragment shader source: Texture2D tex: register(t0); sampler smp: register(s0); float4 main(float2 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 { return tex.Sample(smp, uv) * color; } */ static const uint8_t _scimgui_vs_bin[] = { 68, 88, 66, 67, 204, 137, 115, 177, 245, 67, 161, 195, 58, 224, 90, 35, 76, 123, 88, 146, 1, 0, 0, 0, 244, 3, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 64, 1, 0, 0, 176, 1, 0, 0, 36, 2, 0, 0, 88, 3, 0, 0, 82, 68, 69, 70, 4, 1, 0, 0, 1, 0, 0, 0, 100, 0, 0, 0, 1, 0, 0, 0, 60, 0, 0, 0, 0, 5, 254, 255, 0, 145, 0, 0, 220, 0, 0, 0, 82, 68, 49, 49, 60, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 40, 0, 0, 0, 36, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, 97, 114, 97, 109, 115, 0, 171, 92, 0, 0, 0, 1, 0, 0, 0, 124, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 100, 105, 115, 112, 95, 115, 105, 122, 101, 0, 102, 108, 111, 97, 116, 50, 0, 171, 171, 171, 1, 0, 3, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 49, 48, 46, 49, 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, 3, 3, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 15, 15, 0, 0, 80, 79, 83, 73, 84, 73, 79, 78, 0, 84, 69, 88, 67, 79, 79, 82, 68, 0, 67, 79, 76, 79, 82, 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, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 12, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 84, 69, 88, 67, 79, 79, 82, 68, 0, 67, 79, 76, 79, 82, 0, 83, 86, 95, 80, 111, 115, 105, 116, 105, 111, 110, 0, 171, 83, 72, 69, 88, 44, 1, 0, 0, 80, 0, 1, 0, 75, 0, 0, 0, 106, 8, 0, 1, 89, 0, 0, 4, 70, 142, 32, 0, 0, 0, 0, 0, 1, 0, 0, 0, 95, 0, 0, 3, 50, 16, 16, 0, 0, 0, 0, 0, 95, 0, 0, 3, 50, 16, 16, 0, 1, 0, 0, 0, 95, 0, 0, 3, 242, 16, 16, 0, 2, 0, 0, 0, 101, 0, 0, 3, 50, 32, 16, 0, 0, 0, 0, 0, 101, 0, 0, 3, 242, 32, 16, 0, 1, 0, 0, 0, 103, 0, 0, 4, 242, 32, 16, 0, 2, 0, 0, 0, 1, 0, 0, 0, 104, 0, 0, 2, 1, 0, 0, 0, 54, 0, 0, 5, 50, 32, 16, 0, 0, 0, 0, 0, 70, 16, 16, 0, 1, 0, 0, 0, 54, 0, 0, 5, 242, 32, 16, 0, 1, 0, 0, 0, 70, 30, 16, 0, 2, 0, 0, 0, 14, 0, 0, 8, 50, 0, 16, 0, 0, 0, 0, 0, 70, 16, 16, 0, 0, 0, 0, 0, 70, 128, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 50, 0, 16, 0, 0, 0, 0, 0, 70, 0, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 191, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 10, 50, 32, 16, 0, 2, 0, 0, 0, 70, 0, 16, 0, 0, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 64, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 8, 194, 32, 16, 0, 2, 0, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 128, 63, 62, 0, 0, 1, 83, 84, 65, 84, 148, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const uint8_t _scimgui_fs_bin[] = { 68, 88, 66, 67, 116, 27, 191, 2, 170, 79, 42, 154, 39, 13, 69, 105, 240, 12, 136, 97, 1, 0, 0, 0, 176, 2, 0, 0, 5, 0, 0, 0, 52, 0, 0, 0, 232, 0, 0, 0, 56, 1, 0, 0, 108, 1, 0, 0, 20, 2, 0, 0, 82, 68, 69, 70, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 60, 0, 0, 0, 0, 5, 255, 255, 0, 145, 0, 0, 132, 0, 0, 0, 82, 68, 49, 49, 60, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 40, 0, 0, 0, 36, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 128, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 1, 0, 0, 0, 13, 0, 0, 0, 115, 109, 112, 0, 116, 101, 120, 0, 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, 49, 48, 46, 49, 0, 73, 83, 71, 78, 72, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 15, 15, 0, 0, 84, 69, 88, 67, 79, 79, 82, 68, 0, 67, 79, 76, 79, 82, 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, 160, 0, 0, 0, 80, 0, 0, 0, 40, 0, 0, 0, 106, 8, 0, 1, 90, 0, 0, 3, 0, 96, 16, 0, 0, 0, 0, 0, 88, 24, 0, 4, 0, 112, 16, 0, 0, 0, 0, 0, 85, 85, 0, 0, 98, 16, 0, 3, 50, 16, 16, 0, 0, 0, 0, 0, 98, 16, 0, 3, 242, 16, 16, 0, 1, 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, 139, 194, 0, 0, 128, 67, 85, 21, 0, 242, 0, 16, 0, 0, 0, 0, 0, 70, 16, 16, 0, 0, 0, 0, 0, 70, 126, 16, 0, 0, 0, 0, 0, 0, 96, 16, 0, 0, 0, 0, 0, 56, 0, 0, 7, 242, 32, 16, 0, 0, 0, 0, 0, 70, 14, 16, 0, 0, 0, 0, 0, 70, 30, 16, 0, 1, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, 84, 148, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #else #error "sokol_cimgui.h: No sokol_gfx.h backend selected (SOKOL_GLCORE33, SOKOL_GLES2, SOKOL_GLES3, SOKOL_D3D11 or SOKOL_METAL)" #endif SOKOL_API_IMPL void scimgui_setup(const scimgui_desc_t* desc) { SOKOL_ASSERT(desc); _scimgui_clear(_scimgui); _scimgui.desc = *desc; _scimgui.desc.max_vertices = _scimgui_def(_scimgui.desc.max_vertices, 65536); _scimgui.desc.dpi_scale = _scimgui_def(_scimgui.desc.dpi_scale, 1.0f); /* can keep color_format, depth_format and sample_count as is, since sokol_gfx.h will do its own default-value handling */ /* initialize Dear ImGui */ igCreateContext(NULL); igStyleColorsDark(igGetStyle()); ImGuiIO* io = igGetIO(); if (!_scimgui.desc.no_default_font) { ImFontAtlas_AddFontDefault(io->Fonts, NULL); } io->IniFilename = _scimgui.desc.ini_filename; #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) io->KeyMap[ImGuiKey_Tab] = SAPP_KEYCODE_TAB; io->KeyMap[ImGuiKey_LeftArrow] = SAPP_KEYCODE_LEFT; io->KeyMap[ImGuiKey_RightArrow] = SAPP_KEYCODE_RIGHT; io->KeyMap[ImGuiKey_UpArrow] = SAPP_KEYCODE_UP; io->KeyMap[ImGuiKey_DownArrow] = SAPP_KEYCODE_DOWN; io->KeyMap[ImGuiKey_PageUp] = SAPP_KEYCODE_PAGE_UP; io->KeyMap[ImGuiKey_PageDown] = SAPP_KEYCODE_PAGE_DOWN; io->KeyMap[ImGuiKey_Home] = SAPP_KEYCODE_HOME; io->KeyMap[ImGuiKey_End] = SAPP_KEYCODE_END; io->KeyMap[ImGuiKey_Delete] = SAPP_KEYCODE_DELETE; io->KeyMap[ImGuiKey_Backspace] = SAPP_KEYCODE_BACKSPACE; io->KeyMap[ImGuiKey_Space] = SAPP_KEYCODE_SPACE; io->KeyMap[ImGuiKey_Enter] = SAPP_KEYCODE_ENTER; io->KeyMap[ImGuiKey_Escape] = SAPP_KEYCODE_ESCAPE; io->KeyMap[ImGuiKey_A] = SAPP_KEYCODE_A; io->KeyMap[ImGuiKey_C] = SAPP_KEYCODE_C; io->KeyMap[ImGuiKey_V] = SAPP_KEYCODE_V; io->KeyMap[ImGuiKey_X] = SAPP_KEYCODE_X; io->KeyMap[ImGuiKey_Y] = SAPP_KEYCODE_Y; io->KeyMap[ImGuiKey_Z] = SAPP_KEYCODE_Z; #endif /* create sokol-gfx resources */ sg_push_debug_group("sokol-imgui"); sg_buffer_desc vb_desc; _scimgui_clear(vb_desc); vb_desc.usage = SG_USAGE_STREAM; vb_desc.size = _scimgui.desc.max_vertices * sizeof(ImDrawVert); vb_desc.label = "sokol-imgui-vertices"; _scimgui.vbuf = sg_make_buffer(&vb_desc); sg_buffer_desc ib_desc; _scimgui_clear(ib_desc); ib_desc.type = SG_BUFFERTYPE_INDEXBUFFER; ib_desc.usage = SG_USAGE_STREAM; ib_desc.size = _scimgui.desc.max_vertices * 3 * sizeof(uint16_t); ib_desc.label = "sokol-imgui-indices"; _scimgui.ibuf = sg_make_buffer(&ib_desc); /* default font texture */ if (!_scimgui.desc.no_default_font) { unsigned char* font_pixels; int font_width, font_height, bytes_per_pixel; ImFontAtlas_GetTexDataAsRGBA32(io->Fonts, &font_pixels, &font_width, &font_height, &bytes_per_pixel); sg_image_desc img_desc; _scimgui_clear(img_desc); img_desc.width = font_width; img_desc.height = font_height; img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; img_desc.min_filter = SG_FILTER_LINEAR; img_desc.mag_filter = SG_FILTER_LINEAR; img_desc.content.subimage[0][0].ptr = font_pixels; img_desc.content.subimage[0][0].size = font_width * font_height * sizeof(uint32_t); img_desc.label = "sokol-imgui-font"; _scimgui.img = sg_make_image(&img_desc); io->Fonts->TexID = (ImTextureID)(uintptr_t) _scimgui.img.id; } /* shader object for using the embedded shader source (or bytecode) */ sg_shader_desc shd_desc; _scimgui_clear(shd_desc); sg_shader_uniform_block_desc *ub = &shd_desc.vs.uniform_blocks[0]; ub->size = sizeof(_scimgui_vs_params_t); ub->uniforms[0].name = "disp_size"; ub->uniforms[0].type = SG_UNIFORMTYPE_FLOAT2; shd_desc.attrs[0].name = "position"; shd_desc.attrs[0].sem_name = "POSITION"; shd_desc.attrs[1].name = "texcoord0"; shd_desc.attrs[1].sem_name = "TEXCOORD"; shd_desc.attrs[2].name = "color0"; shd_desc.attrs[2].sem_name = "COLOR"; shd_desc.fs.images[0].name = "tex"; shd_desc.fs.images[0].type = SG_IMAGETYPE_2D; #if defined(SOKOL_D3D11) shd_desc.vs.byte_code = _scimgui_vs_bin; shd_desc.vs.byte_code_size = sizeof(_scimgui_vs_bin); shd_desc.fs.byte_code = _scimgui_fs_bin; shd_desc.fs.byte_code_size = sizeof(_scimgui_fs_bin); #else shd_desc.vs.source = _scimgui_vs_src; shd_desc.fs.source = _scimgui_fs_src; #endif shd_desc.label = "sokol-imgui-shader"; _scimgui.shd = sg_make_shader(&shd_desc); /* pipeline object for imgui rendering */ sg_pipeline_desc pip_desc; _scimgui_clear(pip_desc); pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); { sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[0]; attr->offset = offsetof(ImDrawVert, pos); attr->format = SG_VERTEXFORMAT_FLOAT2; } { sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[1]; attr->offset = offsetof(ImDrawVert, uv); attr->format = SG_VERTEXFORMAT_FLOAT2; } { sg_vertex_attr_desc* attr = &pip_desc.layout.attrs[2]; attr->offset = offsetof(ImDrawVert, col); attr->format = SG_VERTEXFORMAT_UBYTE4N; } pip_desc.shader = _scimgui.shd; pip_desc.index_type = SG_INDEXTYPE_UINT16; pip_desc.blend.enabled = true; pip_desc.blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; pip_desc.blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; pip_desc.blend.color_write_mask = SG_COLORMASK_RGB; pip_desc.blend.color_format = _scimgui.desc.color_format; pip_desc.blend.depth_format = _scimgui.desc.depth_format; pip_desc.rasterizer.sample_count = _scimgui.desc.sample_count; pip_desc.label = "sokol-imgui-pipeline"; _scimgui.pip = sg_make_pipeline(&pip_desc); sg_pop_debug_group(); } SOKOL_API_IMPL void scimgui_shutdown(void) { /* NOTE: it's valid to call the destroy funcs with SG_INVALID_ID */ sg_destroy_pipeline(_scimgui.pip); sg_destroy_shader(_scimgui.shd); sg_destroy_image(_scimgui.img); sg_destroy_buffer(_scimgui.ibuf); sg_destroy_buffer(_scimgui.vbuf); } SOKOL_API_IMPL void scimgui_new_frame(int width, int height, double delta_time) { ImGuiIO* io = igGetIO(); io->DisplaySize.x = ((float) width) * _scimgui.desc.dpi_scale; io->DisplaySize.y = ((float) height) * _scimgui.desc.dpi_scale; io->DeltaTime = (float) delta_time; #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) for (int i = 0; i < SAPP_MAX_MOUSEBUTTONS; i++) { if (_scimgui.btn_down[i]) { _scimgui.btn_down[i] = false; io->MouseDown[i] = true; } else if (_scimgui.btn_up[i]) { _scimgui.btn_up[i] = false; io->MouseDown[i] = false; } } if (io->WantTextInput && !sapp_keyboard_shown()) { sapp_show_keyboard(true); } if (!io->WantTextInput && sapp_keyboard_shown()) { sapp_show_keyboard(false); } #endif igNewFrame(); } SOKOL_API_IMPL void scimgui_render(void) { igRender(); ImDrawData* draw_data = igGetDrawData(); if (draw_data == NULL) { return; } if (draw_data->CmdListsCount == 0) { return; } /* render the ImGui command list */ sg_push_debug_group("sokol-imgui"); const float dpi_scale = _scimgui.desc.dpi_scale; const int fb_width = (const int) (igGetIO()->DisplaySize.x * dpi_scale); const int fb_height = (const int) (igGetIO()->DisplaySize.y * dpi_scale); sg_apply_viewport(0, 0, fb_width, fb_height, true); sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); sg_apply_pipeline(_scimgui.pip); _scimgui_vs_params_t vs_params; vs_params.disp_size.x = igGetIO()->DisplaySize.x; vs_params.disp_size.y = igGetIO()->DisplaySize.y; sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &vs_params, sizeof(vs_params)); sg_bindings bind; _scimgui_clear(bind); bind.vertex_buffers[0] = _scimgui.vbuf; bind.index_buffer = _scimgui.ibuf; ImTextureID tex_id = igGetIO()->Fonts->TexID; bind.fs_images[0].id = (uint32_t)(uintptr_t)tex_id; for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++) { const ImDrawList* cl = draw_data->CmdLists[cl_index]; /* append vertices and indices to buffers, record start offsets in draw state */ const int vtx_size = cl->VtxBuffer.Size * sizeof(ImDrawVert); const int idx_size = cl->IdxBuffer.Size * sizeof(ImDrawIdx); ImVector_ImDrawVert vertex_buffer = cl->VtxBuffer; ImVector_ImDrawIdx draw_idx = cl->IdxBuffer; const int vb_offset = sg_append_buffer(bind.vertex_buffers[0], ImVector_ImDrawVert_front(&vertex_buffer), vtx_size); const int ib_offset = sg_append_buffer(bind.index_buffer, ImVector_ImDrawIdx_front(&draw_idx), idx_size); /* don't render anything if the buffer is in overflow state (this is also checked internally in sokol_gfx, draw calls that attempt to draw with overflowed buffers will be silently dropped) */ if (sg_query_buffer_overflow(bind.vertex_buffers[0]) || sg_query_buffer_overflow(bind.index_buffer)) { break; } bind.vertex_buffer_offsets[0] = vb_offset; bind.index_buffer_offset = ib_offset; sg_apply_bindings(&bind); int base_element = 0; for (int i = 0; i < cl->CmdBuffer.Size; i++) { ImDrawCmd pcmd = cl->CmdBuffer.Data[i]; if (pcmd.UserCallback) { pcmd.UserCallback(cl, &pcmd); } else { if (tex_id != pcmd.TextureId) { tex_id = pcmd.TextureId; bind.fs_images[0].id = (uint32_t)(uintptr_t)tex_id; sg_apply_bindings(&bind); } const int scissor_x = (int) (pcmd.ClipRect.x * dpi_scale); const int scissor_y = (int) (pcmd.ClipRect.y * dpi_scale); const int scissor_w = (int) ((pcmd.ClipRect.z - pcmd.ClipRect.x) * dpi_scale); const int scissor_h = (int) ((pcmd.ClipRect.w - pcmd.ClipRect.y) * dpi_scale); sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); sg_draw(base_element, pcmd.ElemCount, 1); } base_element += pcmd.ElemCount; } } sg_apply_viewport(0, 0, fb_width, fb_height, true); sg_apply_scissor_rect(0, 0, fb_width, fb_height, true); sg_pop_debug_group(); } #if !defined(SOKOL_CIMGUI_NO_SOKOL_APP) SOKOL_API_IMPL bool scimgui_handle_event(const sapp_event* ev) { const float dpi_scale = _scimgui.desc.dpi_scale; ImGuiIO* io = igGetIO(); io->KeyAlt = (ev->modifiers & SAPP_MODIFIER_ALT) != 0; io->KeyCtrl = (ev->modifiers & SAPP_MODIFIER_CTRL) != 0; io->KeyShift = (ev->modifiers & SAPP_MODIFIER_SHIFT) != 0; io->KeySuper = (ev->modifiers & SAPP_MODIFIER_SUPER) != 0; switch (ev->type) { case SAPP_EVENTTYPE_MOUSE_DOWN: io->MousePos.x = ev->mouse_x / dpi_scale; io->MousePos.y = ev->mouse_y / dpi_scale; if (ev->mouse_button < 3) { _scimgui.btn_down[ev->mouse_button] = true; } break; case SAPP_EVENTTYPE_MOUSE_UP: io->MousePos.x = ev->mouse_x / dpi_scale; io->MousePos.y = ev->mouse_y / dpi_scale; if (ev->mouse_button < 3) { _scimgui.btn_up[ev->mouse_button] = true; } break; case SAPP_EVENTTYPE_MOUSE_MOVE: io->MousePos.x = ev->mouse_x / dpi_scale; io->MousePos.y = ev->mouse_y / dpi_scale; break; case SAPP_EVENTTYPE_MOUSE_ENTER: case SAPP_EVENTTYPE_MOUSE_LEAVE: for (int i = 0; i < 3; i++) { _scimgui.btn_down[i] = false; _scimgui.btn_up[i] = false; io->MouseDown[i] = false; } break; case SAPP_EVENTTYPE_MOUSE_SCROLL: io->MouseWheelH = ev->scroll_x; io->MouseWheel = ev->scroll_y; break; case SAPP_EVENTTYPE_TOUCHES_BEGAN: _scimgui.btn_down[0] = true; io->MousePos.x = ev->touches[0].pos_x / dpi_scale; io->MousePos.y = ev->touches[0].pos_y / dpi_scale; break; case SAPP_EVENTTYPE_TOUCHES_MOVED: io->MousePos.x = ev->touches[0].pos_x / dpi_scale; io->MousePos.y = ev->touches[0].pos_y / dpi_scale; break; case SAPP_EVENTTYPE_TOUCHES_ENDED: _scimgui.btn_up[0] = true; io->MousePos.x = ev->touches[0].pos_x / dpi_scale; io->MousePos.y = ev->touches[0].pos_y / dpi_scale; break; case SAPP_EVENTTYPE_TOUCHES_CANCELLED: _scimgui.btn_up[0] = _scimgui.btn_down[0] = false; break; case SAPP_EVENTTYPE_KEY_DOWN: io->KeysDown[ev->key_code] = true; break; case SAPP_EVENTTYPE_KEY_UP: io->KeysDown[ev->key_code] = false; break; case SAPP_EVENTTYPE_CHAR: ImGuiIO_AddInputCharacter(io, (ImWchar)ev->char_code); break; default: break; } return io->WantCaptureKeyboard; } #endif #endif /* SOKOL_IMPL */