├── .gitattributes ├── .gitignore └── code ├── build.bat ├── build.sh ├── build.zig ├── c.zig ├── carbon.zig ├── cimgui ├── cimgui.cpp ├── cimgui.h └── imgui │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_internal.h │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ ├── imstb_truetype.h │ └── misc │ ├── README.txt │ ├── cpp │ ├── README.txt │ ├── imgui_stdlib.cpp │ └── imgui_stdlib.h │ ├── fonts │ ├── Cousine-Regular.ttf │ ├── DroidSans.ttf │ ├── Karla-Regular.ttf │ ├── ProggyClean.ttf │ ├── ProggyTiny.ttf │ ├── README.txt │ ├── Roboto-Medium.ttf │ └── binary_to_compressed_c.cpp │ ├── freetype │ ├── README.md │ ├── imgui_freetype.cpp │ └── imgui_freetype.h │ └── natvis │ ├── README.txt │ └── imgui.natvis ├── common.zig ├── compile_cimgui.cpp ├── serialize.zig ├── sokol ├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── fips.yml ├── sokol_app.h ├── sokol_args.h ├── sokol_audio.h ├── sokol_fetch.h ├── sokol_gfx.h ├── sokol_imgui.h ├── sokol_time.h └── util │ ├── README.md │ ├── sokol_fontstash.h │ ├── sokol_gfx_imgui.h │ ├── sokol_gl.h │ └── sokol_imgui.h └── sokol_compile.c /.gitattributes: -------------------------------------------------------------------------------- 1 | *.zig -crlf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | code/zig-cache/ 3 | -------------------------------------------------------------------------------- /code/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem pushd ..\build\ 4 | rem clang++ -c -g -gcodeview -Wno-deprecated-declarations -Wno-return-type-c-linkage ..\code\cimgui\imgui\imgui.cpp -I ..\code\cimgui -o imgui.obj 5 | rem clang++ -c -g -gcodeview -Wno-deprecated-declarations -Wno-return-type-c-linkage ..\code\cimgui\imgui\imgui_demo.cpp -I ..\code\cimgui -o imgui_demo.obj 6 | rem clang++ -c -g -gcodeview -Wno-deprecated-declarations -Wno-return-type-c-linkage ..\code\cimgui\imgui\imgui_draw.cpp -I ..\code\cimgui -o imgui_draw.obj 7 | rem clang++ -c -g -gcodeview -Wno-deprecated-declarations -Wno-return-type-c-linkage ..\code\cimgui\imgui\imgui_widgets.cpp -I ..\code\cimgui -o imgui_widgets.obj 8 | rem clang++ -c -g -gcodeview -Wno-deprecated-declarations -Wno-return-type-c-linkage ..\code\cimgui\cimgui.cpp -I ..\code\cimgui -o cimgui.obj 9 | rem popd 10 | rem clang -g -gcodeview -std=c99 ..\code\carbon.c cimgui.obj imgui.obj imgui_demo.obj imgui_draw.obj imgui_widgets.obj -I ..\code\sokol -o carbon.exe -l user32.lib -l gdi32.lib 11 | C:\zig\zig.exe build 12 | -------------------------------------------------------------------------------- /code/build.sh: -------------------------------------------------------------------------------- 1 | #../../zig/build/bin/zig build 2 | 3 | clang carbon.c -o ../build/carbon -lX11 -ldl -lGL -lGLEW ../code/cimgui/cimgui.so -Wl,-rpath,../code/cimgui/ 4 | -------------------------------------------------------------------------------- /code/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const builtin = @import("builtin"); 3 | 4 | const build_root = "../build/"; 5 | const cache_root = "../build/cache/"; 6 | 7 | const is_windows = builtin.os == builtin.Os.windows; 8 | 9 | pub fn build(b: *std.build.Builder) void { 10 | b.build_root = build_root; 11 | b.cache_root = cache_root; 12 | b.release_mode = builtin.Mode.Debug; 13 | 14 | const mode = b.standardReleaseOptions(); 15 | 16 | var exe = b.addExecutable("carbon", "../code/carbon.zig"); 17 | exe.setOutputDir(build_root); 18 | exe.addIncludeDir("../code/"); 19 | exe.setBuildMode(mode); 20 | exe.addCSourceFile("../code/sokol_compile.c", [_][]const u8{"-std=c99"}); 21 | 22 | exe.linkSystemLibrary("c"); 23 | if (is_windows) { 24 | exe.addObjectFile("cimgui.obj"); 25 | exe.addObjectFile("imgui.obj"); 26 | exe.addObjectFile("imgui_demo.obj"); 27 | exe.addObjectFile("imgui_draw.obj"); 28 | exe.addObjectFile("imgui_widgets.obj"); 29 | exe.linkSystemLibrary("user32"); 30 | exe.linkSystemLibrary("gdi32"); 31 | } else { 32 | exe.linkSystemLibrary("GL"); 33 | exe.linkSystemLibrary("GLEW"); 34 | } 35 | 36 | var run_step = exe.run(); 37 | run_step.step.dependOn(&exe.step); 38 | 39 | b.default_step.dependOn(&run_step.step); 40 | } 41 | -------------------------------------------------------------------------------- /code/c.zig: -------------------------------------------------------------------------------- 1 | pub usingnamespace @cImport({ 2 | @cDefine("SOKOL_GLCORE33", ""); 3 | @cInclude("sokol/sokol_app.h"); 4 | @cInclude("sokol/sokol_gfx.h"); 5 | @cInclude("sokol/sokol_time.h"); 6 | @cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", ""); 7 | @cInclude("cimgui/cimgui.h"); 8 | @cInclude("sokol/sokol_imgui.h"); 9 | }); 10 | -------------------------------------------------------------------------------- /code/carbon.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const c = @import("c.zig"); 4 | const serialize = @import("serialize.zig"); 5 | 6 | fn zero_struct(comptime T: type) T { 7 | var variable: T = undefined; 8 | @memset(@ptrCast([*]u8, &variable), 0, @sizeOf(T)); 9 | 10 | return variable; 11 | } 12 | 13 | const State = struct { 14 | pass_action: c.sg_pass_action, 15 | main_pipeline: c.sg_pipeline, 16 | main_bindings: c.sg_bindings, 17 | }; 18 | 19 | var state: State = undefined; 20 | 21 | export fn init() void { 22 | var desc = zero_struct(c.sg_desc); 23 | c.sg_setup(&desc); 24 | 25 | c.stm_setup(); 26 | 27 | var imgui_desc = zero_struct(c.simgui_desc_t); 28 | c.simgui_setup(&imgui_desc); 29 | 30 | state.pass_action.colors[0].action = c.SG_ACTION_CLEAR; 31 | state.pass_action.colors[0].val = [_]f32{ 0.2, 0.2, 0.2, 1.0 }; 32 | 33 | const vertices = [_]f32{ 34 | // positions // colors 35 | 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 36 | 0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 37 | -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 38 | }; 39 | 40 | var buffer_desc = zero_struct(c.sg_buffer_desc); 41 | buffer_desc.size = vertices.len * @sizeOf(f32); 42 | buffer_desc.content = &vertices[0]; 43 | buffer_desc.type = c.SG_BUFFERTYPE_VERTEXBUFFER; 44 | buffer_desc.label = c"triangle_vertices"; 45 | state.main_bindings.vertex_buffers[0] = c.sg_make_buffer(&buffer_desc); 46 | 47 | var shader_desc = zero_struct(c.sg_shader_desc); 48 | shader_desc.vs.source = 49 | c\\#version 330 50 | c\\in vec3 vertex_position; 51 | c\\in vec4 in_color; 52 | c\\out vec4 color; 53 | c\\void main(void) 54 | c\\{ 55 | c\\ gl_Position = vec4(vertex_position, 1.0); 56 | c\\ color = in_color; 57 | c\\} 58 | ; 59 | shader_desc.fs.source = 60 | c\\#version 330 61 | c\\out vec4 frag_color; 62 | c\\in vec4 color; 63 | c\\void main(void) 64 | c\\{ 65 | c\\ frag_color = color; 66 | c\\} 67 | ; 68 | 69 | const shader = c.sg_make_shader(&shader_desc); 70 | 71 | var pipeline_desc = zero_struct(c.sg_pipeline_desc); 72 | pipeline_desc.layout.attrs[0].format = c.SG_VERTEXFORMAT_FLOAT3; 73 | pipeline_desc.layout.attrs[1].format = c.SG_VERTEXFORMAT_FLOAT4; 74 | pipeline_desc.shader = shader; 75 | pipeline_desc.label = c"main_pipeline"; 76 | state.main_pipeline = c.sg_make_pipeline(&pipeline_desc); 77 | } 78 | 79 | var last_time: u64 = 0; 80 | var show_test_window: bool = false; 81 | var show_another_window: bool = false; 82 | var display_menu: bool = false; 83 | 84 | var f: f32 = 0.0; 85 | 86 | export fn update() void { 87 | const width = c.sapp_width(); 88 | const height = c.sapp_height(); 89 | const dt = c.stm_sec(c.stm_laptime(&last_time)); 90 | c.simgui_new_frame(width, height, dt); 91 | 92 | if (display_menu) { 93 | c.igSetNextWindowPos(zero_struct(c.ImVec2), 0, zero_struct(c.ImVec2)); 94 | c.igSetNextWindowSize(c.ImVec2{ .x = @intToFloat(f32, width), .y = @intToFloat(f32, height) }, 0); 95 | 96 | _ = c.igBegin(c"Window", null, @enumToInt(c.ImGuiWindowFlags_NoTitleBar) | @enumToInt(c.ImGuiWindowFlags_NoBringToFrontOnFocus) | @enumToInt(c.ImGuiWindowFlags_NoResize) | @enumToInt(c.ImGuiWindowFlags_NoMove) | @enumToInt(c.ImGuiWindowFlags_AlwaysAutoResize)); 97 | serialize.serialize_imgui(state, "state"); 98 | 99 | c.igEnd(); 100 | } else { 101 | c.igText(c"Hello, world!"); 102 | _ = c.igSliderFloat(c"float", &f, 0.0, 1.0, c"%.3f", 1.0); 103 | _ = c.igColorEdit3(c"clear color", &state.pass_action.colors[0].val[0], 0); 104 | if (c.igButton(c"Test Window", c.ImVec2{ .x = 0.0, .y = 0.0 })) show_test_window = !show_test_window; 105 | if (c.igButton(c"Another Window", c.ImVec2{ .x = 0.0, .y = 0.0 })) show_another_window = !show_another_window; 106 | c.igText(c"Application average %.3f ms/frame (%.1f FPS)", 1000.0 / c.igGetIO().*.Framerate, c.igGetIO().*.Framerate); 107 | 108 | if (show_another_window) { 109 | c.igSetNextWindowSize(c.ImVec2{ .x = 200, .y = 100 }, @intCast(c_int, @enumToInt(c.ImGuiCond_FirstUseEver))); 110 | _ = c.igBegin(c"Another Window", &show_another_window, 0); 111 | c.igText(c"Hello"); 112 | c.igEnd(); 113 | } 114 | 115 | if (show_test_window) { 116 | c.igSetNextWindowPos(c.ImVec2{ .x = 460, .y = 20 }, @intCast(c_int, @enumToInt(c.ImGuiCond_FirstUseEver)), c.ImVec2{ .x = 0, .y = 0 }); 117 | c.igShowDemoWindow(0); 118 | } 119 | } 120 | 121 | c.sg_begin_default_pass(&state.pass_action, width, height); 122 | c.sg_apply_pipeline(state.main_pipeline); 123 | c.sg_apply_bindings(&state.main_bindings); 124 | c.sg_draw(0, 3, 1); 125 | c.simgui_render(); 126 | c.sg_end_pass(); 127 | c.sg_commit(); 128 | } 129 | 130 | export fn cleanup() void { 131 | c.simgui_shutdown(); 132 | c.sg_shutdown(); 133 | } 134 | 135 | export fn event(e: [*c]const c.sapp_event) void { 136 | _ = c.simgui_handle_event(e); 137 | 138 | if (e[0].type == c.sapp_event_type.SAPP_EVENTTYPE_KEY_DOWN and 139 | e[0].key_code == c.sapp_keycode.SAPP_KEYCODE_TAB) 140 | { 141 | display_menu = !display_menu; 142 | } 143 | } 144 | 145 | export fn sokol_main() c.sapp_desc { 146 | var app_desc = zero_struct(c.sapp_desc); 147 | app_desc.width = 640; 148 | app_desc.height = 480; 149 | app_desc.init_cb = init; 150 | app_desc.frame_cb = update; 151 | app_desc.cleanup_cb = cleanup; 152 | app_desc.event_cb = event; 153 | 154 | return app_desc; 155 | } 156 | -------------------------------------------------------------------------------- /code/cimgui/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) 7 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 8 | // If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include 9 | // the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 10 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 11 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 12 | //----------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 18 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 19 | 20 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 21 | // Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 22 | //#define IMGUI_API __declspec( dllexport ) 23 | //#define IMGUI_API __declspec( dllimport ) 24 | 25 | //---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 26 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 27 | 28 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 29 | // It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. 30 | //#define IMGUI_DISABLE_DEMO_WINDOWS 31 | //#define IMGUI_DISABLE_METRICS_WINDOW 32 | 33 | //---- Don't implement some functions to reduce linkage requirements. 34 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 35 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 36 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 37 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices'). 38 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. 39 | //#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. 40 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 41 | 42 | //---- Include imgui_user.h at the end of imgui.h as a convenience 43 | //#define IMGUI_INCLUDE_IMGUI_USER_H 44 | 45 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 46 | //#define IMGUI_USE_BGRA_PACKED_COLOR 47 | 48 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 49 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 50 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 51 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 52 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 53 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 54 | 55 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 56 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 57 | /* 58 | #define IM_VEC2_CLASS_EXTRA \ 59 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 60 | operator MyVec2() const { return MyVec2(x,y); } 61 | 62 | #define IM_VEC4_CLASS_EXTRA \ 63 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 64 | operator MyVec4() const { return MyVec4(x,y,z,w); } 65 | */ 66 | 67 | //---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices. 68 | // Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bits indices). 69 | // Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer. 70 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 71 | //#define ImDrawIdx unsigned int 72 | 73 | //---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) 74 | //struct ImDrawList; 75 | //struct ImDrawCmd; 76 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 77 | //#define ImDrawCallback MyImDrawCallback 78 | 79 | //---- Debug Tools 80 | // Use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging. 81 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 82 | //#define IM_DEBUG_BREAK __debugbreak() 83 | // Have the Item Picker break in the ItemAdd() function instead of ItemHoverable() - which is earlier in the code, will catch a few extra items, allow picking items other than Hovered one. 84 | // This adds a small runtime cost which is why it is not enabled by default. 85 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 86 | 87 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 88 | /* 89 | namespace ImGui 90 | { 91 | void MyFunction(const char* name, const MyMatrix44& v); 92 | } 93 | */ 94 | -------------------------------------------------------------------------------- /code/cimgui/imgui/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/README.txt: -------------------------------------------------------------------------------- 1 | 2 | misc/cpp/ 3 | InputText() wrappers for C++ standard library (STL) type: std::string. 4 | This is also an example of how you may wrap your own similar types. 5 | 6 | misc/fonts/ 7 | Fonts loading/merging instructions (e.g. How to handle glyph ranges, how to merge icons fonts). 8 | Command line tool "binary_to_compressed_c" to create compressed arrays to embed data in source code. 9 | Suggested fonts and links. 10 | 11 | misc/freetype/ 12 | Font atlas builder/rasterizer using FreeType instead of stb_truetype. 13 | Benefit from better FreeType rasterization, in particular for small fonts. 14 | 15 | misc/natvis/ 16 | Natvis file to describe dear imgui types in the Visual Studio debugger. 17 | With this, types like ImVector<> will be displayed nicely in the debugger. 18 | You can include this file a Visual Studio project file, or install it in Visual Studio folder. 19 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/cpp/README.txt: -------------------------------------------------------------------------------- 1 | 2 | imgui_stdlib.h + imgui_stdlib.cpp 3 | InputText() wrappers for C++ standard library (STL) type: std::string. 4 | This is also an example of how you may wrap your own similar types. 5 | 6 | imgui_scoped.h 7 | [Experimental, not currently in main repository] 8 | Additional header file with some RAII-style wrappers for common Dear ImGui functions. 9 | Try by merging: https://github.com/ocornut/imgui/pull/2197 10 | Discuss at: https://github.com/ocornut/imgui/issues/2096 11 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/cpp/imgui_stdlib.cpp: -------------------------------------------------------------------------------- 1 | // imgui_stdlib.cpp 2 | // Wrappers for C++ standard library (STL) types (std::string, etc.) 3 | // This is also an example of how you may wrap your own similar types. 4 | 5 | // Compatibility: 6 | // - std::string support is only guaranteed to work from C++11. 7 | // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) 8 | 9 | // Changelog: 10 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 11 | 12 | #include "imgui.h" 13 | #include "imgui_stdlib.h" 14 | 15 | struct InputTextCallback_UserData 16 | { 17 | std::string* Str; 18 | ImGuiInputTextCallback ChainCallback; 19 | void* ChainCallbackUserData; 20 | }; 21 | 22 | static int InputTextCallback(ImGuiInputTextCallbackData* data) 23 | { 24 | InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData; 25 | if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 26 | { 27 | // Resize string callback 28 | // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want. 29 | std::string* str = user_data->Str; 30 | IM_ASSERT(data->Buf == str->c_str()); 31 | str->resize(data->BufTextLen); 32 | data->Buf = (char*)str->c_str(); 33 | } 34 | else if (user_data->ChainCallback) 35 | { 36 | // Forward to user callback, if any 37 | data->UserData = user_data->ChainCallbackUserData; 38 | return user_data->ChainCallback(data); 39 | } 40 | return 0; 41 | } 42 | 43 | bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 44 | { 45 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 46 | flags |= ImGuiInputTextFlags_CallbackResize; 47 | 48 | InputTextCallback_UserData cb_user_data; 49 | cb_user_data.Str = str; 50 | cb_user_data.ChainCallback = callback; 51 | cb_user_data.ChainCallbackUserData = user_data; 52 | return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 53 | } 54 | 55 | bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 56 | { 57 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 58 | flags |= ImGuiInputTextFlags_CallbackResize; 59 | 60 | InputTextCallback_UserData cb_user_data; 61 | cb_user_data.Str = str; 62 | cb_user_data.ChainCallback = callback; 63 | cb_user_data.ChainCallbackUserData = user_data; 64 | return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); 65 | } 66 | 67 | bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 68 | { 69 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 70 | flags |= ImGuiInputTextFlags_CallbackResize; 71 | 72 | InputTextCallback_UserData cb_user_data; 73 | cb_user_data.Str = str; 74 | cb_user_data.ChainCallback = callback; 75 | cb_user_data.ChainCallbackUserData = user_data; 76 | return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 77 | } 78 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/cpp/imgui_stdlib.h: -------------------------------------------------------------------------------- 1 | // imgui_stdlib.h 2 | // Wrappers for C++ standard library (STL) types (std::string, etc.) 3 | // This is also an example of how you may wrap your own similar types. 4 | 5 | // Compatibility: 6 | // - std::string support is only guaranteed to work from C++11. 7 | // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) 8 | 9 | // Changelog: 10 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | namespace ImGui 17 | { 18 | // ImGui::InputText() with std::string 19 | // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity 20 | IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 21 | IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 22 | IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 23 | } 24 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/Cousine-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/Cousine-Regular.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/DroidSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/DroidSans.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/Karla-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/Karla-Regular.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/ProggyClean.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/ProggyClean.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/ProggyTiny.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/ProggyTiny.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/README.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------- 2 | dear imgui, v1.73 3 | ---------------------------------------------------------------------- 4 | misc/fonts/README.txt 5 | This is the Readme dedicated to fonts. 6 | ---------------------------------------------------------------------- 7 | 8 | The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer), 9 | a 13 pixels high, pixel-perfect font used by default. 10 | We embed it font in source code so you can use Dear ImGui without any file system access. 11 | 12 | You may also load external .TTF/.OTF files. 13 | The files in this folder are suggested fonts, provided as a convenience. 14 | 15 | Fonts are rasterized in a single texture at the time of calling either of io.Fonts->GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). 16 | Also read dear imgui FAQ in imgui.cpp! 17 | 18 | If you have other loading/merging/adding fonts, you can post on the Dear ImGui "Getting Started" forum: 19 | https://discourse.dearimgui.org/c/getting-started 20 | 21 | 22 | --------------------------------------- 23 | INDEX: 24 | --------------------------------------- 25 | 26 | - Readme First / FAQ 27 | - Using Icons 28 | - Fonts Loading Instructions 29 | - FreeType rasterizer, Small font sizes 30 | - Building Custom Glyph Ranges 31 | - Using custom colorful icons 32 | - Embedding Fonts in Source Code 33 | - Credits/Licences for fonts included in this folder 34 | - Fonts Links 35 | 36 | 37 | --------------------------------------- 38 | README FIRST / FAQ 39 | --------------------------------------- 40 | 41 | - You can use the style editor ImGui::ShowStyleEditor() in the "Fonts" section to browse your fonts 42 | and understand what's going on if you have an issue. 43 | - Make sure your font ranges data are persistent (available during the call to GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). 44 | - Use C++11 u8"my text" syntax to encode literal strings as UTF-8. e.g.: 45 | u8"hello" 46 | u8"こんにちは" // this will be encoded as UTF-8 47 | - If you want to include a backslash \ character in your string literal, you need to double them e.g. "folder\\filename". 48 | - Please use the Discourse forum (https://discourse.dearimgui.org) and not the Github issue tracker for basic font loading questions. 49 | 50 | 51 | --------------------------------------- 52 | USING ICONS 53 | --------------------------------------- 54 | 55 | Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons) 56 | is an easy and practical way to use icons in your Dear ImGui application. 57 | A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without 58 | having to change fonts back and forth. 59 | 60 | To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: 61 | https://github.com/juliettef/IconFontCppHeaders 62 | 63 | The C++11 version of those files uses the u8"" utf-8 encoding syntax + \u 64 | #define ICON_FA_SEARCH u8"\uf002" 65 | The pre-C++11 version has the values directly encoded as utf-8: 66 | #define ICON_FA_SEARCH "\xEF\x80\x82" 67 | 68 | Example Setup: 69 | 70 | // Merge icons into default tool font 71 | #include "IconsFontAwesome.h" 72 | ImGuiIO& io = ImGui::GetIO(); 73 | io.Fonts->AddFontDefault(); 74 | 75 | ImFontConfig config; 76 | config.MergeMode = true; 77 | config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced 78 | static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; 79 | io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); 80 | 81 | Example Usage: 82 | 83 | // Usage, e.g. 84 | ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); 85 | ImGui::Button(ICON_FA_SEARCH " Search"); 86 | // C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" 87 | // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" 88 | 89 | See Links below for other icons fonts and related tools. 90 | 91 | 92 | --------------------------------------- 93 | FONTS LOADING INSTRUCTIONS 94 | --------------------------------------- 95 | 96 | Load default font: 97 | 98 | ImGuiIO& io = ImGui::GetIO(); 99 | io.Fonts->AddFontDefault(); 100 | 101 | Load .TTF/.OTF file with: 102 | 103 | ImGuiIO& io = ImGui::GetIO(); 104 | ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); 105 | ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); 106 | 107 | // Select font at runtime 108 | ImGui::Text("Hello"); // use the default font (which is the first loaded font) 109 | ImGui::PushFont(font2); 110 | ImGui::Text("Hello with another font"); 111 | ImGui::PopFont(); 112 | 113 | For advanced options create a ImFontConfig structure and pass it to the AddFont function (it will be copied internally): 114 | 115 | ImFontConfig config; 116 | config.OversampleH = 2; 117 | config.OversampleV = 1; 118 | config.GlyphExtraSpacing.x = 1.0f; 119 | ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); 120 | 121 | Read about oversampling here: 122 | https://github.com/nothings/stb/blob/master/tests/oversample 123 | 124 | If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. 125 | The typical result of failing to upload a texture is if every glyphs appears as white rectangles. 126 | In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you 127 | set OversampleH/OversampleV to 1 and use a small font size. 128 | Mind the fact that some graphics drivers have texture size limitation. 129 | If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. 130 | Some solutions: 131 | 132 | - 1) Reduce glyphs ranges by calculating them from source localization data. 133 | You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! 134 | - 2) You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. 135 | - 3) Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). 136 | - 4) Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. 137 | 138 | Combine two fonts into one: 139 | 140 | // Load a first font 141 | ImFont* font = io.Fonts->AddFontDefault(); 142 | 143 | // Add character ranges and merge into the previous font 144 | // The ranges array is not copied by the AddFont* functions and is used lazily 145 | // so ensure it is available at the time of building or calling GetTexDataAsRGBA32(). 146 | static const ImWchar icons_ranges[] = { 0xf000, 0xf3ff, 0 }; // Will not be copied by AddFont* so keep in scope. 147 | ImFontConfig config; 148 | config.MergeMode = true; 149 | io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 18.0f, &config, io.Fonts->GetGlyphRangesJapanese()); 150 | io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 18.0f, &config, icons_ranges); 151 | io.Fonts->Build(); 152 | 153 | Add a fourth parameter to bake specific font ranges only: 154 | 155 | // Basic Latin, Extended Latin 156 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); 157 | 158 | // Default + Selection of 2500 Ideographs used by Simplified Chinese 159 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); 160 | 161 | // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs 162 | io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); 163 | 164 | See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges. 165 | Offset font vertically by altering the io.Font->DisplayOffset value: 166 | 167 | ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); 168 | font->DisplayOffset.y = 1; // Render 1 pixel down 169 | 170 | 171 | --------------------------------------- 172 | FREETYPE RASTERIZER, SMALL FONT SIZES 173 | --------------------------------------- 174 | 175 | Dear ImGui uses imstb_truetype.h to rasterize fonts (with optional oversampling). 176 | This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a 177 | little blurry or hard to read. 178 | 179 | There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder. 180 | 181 | FreeType supports auto-hinting which tends to improve the readability of small fonts. 182 | Note that this code currently creates textures that are unoptimally too large (could be fixed with some work). 183 | Also note that correct sRGB space blending will have an important effect on your font rendering quality. 184 | 185 | 186 | --------------------------------------- 187 | BUILDING CUSTOM GLYPH RANGES 188 | --------------------------------------- 189 | 190 | You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. 191 | For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. 192 | 193 | ImVector ranges; 194 | ImFontGlyphRangesBuilder builder; 195 | builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) 196 | builder.AddChar(0x7262); // Add a specific character 197 | builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges 198 | builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) 199 | 200 | io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); 201 | io.Fonts->Build(); // Build the atlas while 'ranges' is still in scope and not deleted. 202 | 203 | 204 | --------------------------------------- 205 | USING CUSTOM COLORFUL ICONS 206 | --------------------------------------- 207 | 208 | (This is a BETA api, use if you are familiar with dear imgui and with your rendering back-end) 209 | 210 | You can use the ImFontAtlas::AddCustomRect() and ImFontAtlas::AddCustomRectFontGlyph() api to register rectangles 211 | that will be packed into the font atlas texture. Register them before building the atlas, then call Build(). 212 | You can then use ImFontAtlas::GetCustomRectByIndex(int) to query the position/size of your rectangle within the 213 | texture, and blit/copy any graphics data of your choice into those rectangles. 214 | 215 | Pseudo-code: 216 | 217 | // Add font, then register two custom 13x13 rectangles mapped to glyph 'a' and 'b' of this font 218 | ImFont* font = io.Fonts->AddFontDefault(); 219 | int rect_ids[2]; 220 | rect_ids[0] = io.Fonts->AddCustomRectFontGlyph(font, 'a', 13, 13, 13+1); 221 | rect_ids[1] = io.Fonts->AddCustomRectFontGlyph(font, 'b', 13, 13, 13+1); 222 | 223 | // Build atlas 224 | io.Fonts->Build(); 225 | 226 | // Retrieve texture in RGBA format 227 | unsigned char* tex_pixels = NULL; 228 | int tex_width, tex_height; 229 | io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_width, &tex_height); 230 | 231 | for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) 232 | { 233 | int rect_id = rects_ids[rect_n]; 234 | if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) 235 | { 236 | // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here!) 237 | for (int y = 0; y < rect->Height; y++) 238 | { 239 | ImU32* p = (ImU32*)tex_pixels + (rect->Y + y) * tex_width + (rect->X); 240 | for (int x = rect->Width; x > 0; x--) 241 | *p++ = IM_COL32(255, 0, 0, 255); 242 | } 243 | } 244 | } 245 | 246 | 247 | --------------------------------------- 248 | EMBEDDING FONTS IN SOURCE CODE 249 | --------------------------------------- 250 | 251 | Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array that you can embed in source code. 252 | See the documentation in binary_to_compressed_c.cpp for instruction on how to use the tool. 253 | You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README). 254 | The tool can optionally output Base85 encoding to reduce the size of _source code_ but the read-only arrays in the 255 | actual binary will be about 20% bigger. 256 | 257 | Then load the font with: 258 | ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); 259 | or: 260 | ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); 261 | 262 | 263 | --------------------------------------- 264 | CREDITS/LICENSES FOR FONTS INCLUDED IN THIS FOLDER 265 | --------------------------------------- 266 | 267 | Roboto-Medium.ttf 268 | 269 | Apache License 2.0 270 | by Christian Robertson 271 | https://fonts.google.com/specimen/Roboto 272 | 273 | Cousine-Regular.ttf 274 | 275 | by Steve Matteson 276 | Digitized data copyright (c) 2010 Google Corporation. 277 | Licensed under the SIL Open Font License, Version 1.1 278 | https://fonts.google.com/specimen/Cousine 279 | 280 | DroidSans.ttf 281 | 282 | Copyright (c) Steve Matteson 283 | Apache License, version 2.0 284 | https://www.fontsquirrel.com/fonts/droid-sans 285 | 286 | ProggyClean.ttf 287 | 288 | Copyright (c) 2004, 2005 Tristan Grimmer 289 | MIT License 290 | recommended loading setting: Size = 13.0, DisplayOffset.Y = +1 291 | http://www.proggyfonts.net/ 292 | 293 | ProggyTiny.ttf 294 | Copyright (c) 2004, 2005 Tristan Grimmer 295 | MIT License 296 | recommended loading setting: Size = 10.0, DisplayOffset.Y = +1 297 | http://www.proggyfonts.net/ 298 | 299 | Karla-Regular.ttf 300 | Copyright (c) 2012, Jonathan Pinhorn 301 | SIL OPEN FONT LICENSE Version 1.1 302 | 303 | 304 | --------------------------------------- 305 | FONTS LINKS 306 | --------------------------------------- 307 | 308 | ICON FONTS 309 | 310 | C/C++ header for icon fonts (#define with code points to use in source code string literals) 311 | https://github.com/juliettef/IconFontCppHeaders 312 | 313 | FontAwesome 314 | https://fortawesome.github.io/Font-Awesome 315 | 316 | OpenFontIcons 317 | https://github.com/traverseda/OpenFontIcons 318 | 319 | Google Icon Fonts 320 | https://design.google.com/icons/ 321 | 322 | Kenney Icon Font (Game Controller Icons) 323 | https://github.com/nicodinh/kenney-icon-font 324 | 325 | IcoMoon - Custom Icon font builder 326 | https://icomoon.io/app 327 | 328 | REGULAR FONTS 329 | 330 | Google Noto Fonts (worldwide languages) 331 | https://www.google.com/get/noto/ 332 | 333 | Open Sans Fonts 334 | https://fonts.google.com/specimen/Open+Sans 335 | 336 | (Japanese) M+ fonts by Coji Morishita are free 337 | http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html 338 | 339 | MONOSPACE FONTS 340 | 341 | (Pixel Perfect) Proggy Fonts, by Tristan Grimmer 342 | http://www.proggyfonts.net or http://upperbounds.net 343 | 344 | (Pixel Perfect) Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) 345 | https://github.com/kmar/Sweet16Font 346 | Also include .inl file to use directly in dear imgui. 347 | 348 | Google Noto Mono Fonts 349 | https://www.google.com/get/noto/ 350 | 351 | Typefaces for source code beautification 352 | https://github.com/chrissimpkins/codeface 353 | 354 | Programmation fonts 355 | http://s9w.github.io/font_compare/ 356 | 357 | Inconsolata 358 | http://www.levien.com/type/myfonts/inconsolata.html 359 | 360 | Adobe Source Code Pro: Monospaced font family for user interface and coding environments 361 | https://github.com/adobe-fonts/source-code-pro 362 | 363 | Monospace/Fixed Width Programmer's Fonts 364 | http://www.lowing.org/fonts/ 365 | 366 | 367 | Or use Arial Unicode or other Unicode fonts provided with Windows for full characters coverage (not sure of their licensing). 368 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rivten/carbon/5516bdee066aca2cd182d58b936fe3f691ed0deb/code/cimgui/imgui/misc/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/fonts/binary_to_compressed_c.cpp: -------------------------------------------------------------------------------- 1 | // ImGui - binary_to_compressed_c.cpp 2 | // Helper tool to turn a file into a C array, if you want to embed font data in your source code. 3 | 4 | // The data is first compressed with stb_compress() to reduce source code size, 5 | // then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) 6 | // (If we used 32-bits constants it would require take 11 bytes of source code to encode 4 bytes, and be endianness dependent) 7 | // Note that even with compression, the output array is likely to be bigger than the binary file.. 8 | // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() 9 | 10 | // Build with, e.g: 11 | // # cl.exe binary_to_compressed_c.cpp 12 | // # gcc binary_to_compressed_c.cpp 13 | // You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui 14 | 15 | // Usage: 16 | // binary_to_compressed_c.exe [-base85] [-nocompress] 17 | // Usage example: 18 | // # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp 19 | // # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp 20 | 21 | #define _CRT_SECURE_NO_WARNINGS 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // stb_compress* from stb.h - declaration 28 | typedef unsigned int stb_uint; 29 | typedef unsigned char stb_uchar; 30 | stb_uint stb_compress(stb_uchar *out,stb_uchar *in,stb_uint len); 31 | 32 | static bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression); 33 | 34 | int main(int argc, char** argv) 35 | { 36 | if (argc < 3) 37 | { 38 | printf("Syntax: %s [-base85] [-nocompress] \n", argv[0]); 39 | return 0; 40 | } 41 | 42 | int argn = 1; 43 | bool use_base85_encoding = false; 44 | bool use_compression = true; 45 | if (argv[argn][0] == '-') 46 | { 47 | if (strcmp(argv[argn], "-base85") == 0) { use_base85_encoding = true; argn++; } 48 | else if (strcmp(argv[argn], "-nocompress") == 0) { use_compression = false; argn++; } 49 | else 50 | { 51 | fprintf(stderr, "Unknown argument: '%s'\n", argv[argn]); 52 | return 1; 53 | } 54 | } 55 | 56 | bool ret = binary_to_compressed_c(argv[argn], argv[argn+1], use_base85_encoding, use_compression); 57 | if (!ret) 58 | fprintf(stderr, "Error opening or reading file: '%s'\n", argv[argn]); 59 | return ret ? 0 : 1; 60 | } 61 | 62 | char Encode85Byte(unsigned int x) 63 | { 64 | x = (x % 85) + 35; 65 | return (x>='\\') ? x+1 : x; 66 | } 67 | 68 | bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression) 69 | { 70 | // Read file 71 | FILE* f = fopen(filename, "rb"); 72 | if (!f) return false; 73 | int data_sz; 74 | if (fseek(f, 0, SEEK_END) || (data_sz = (int)ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) { fclose(f); return false; } 75 | char* data = new char[data_sz+4]; 76 | if (fread(data, 1, data_sz, f) != (size_t)data_sz) { fclose(f); delete[] data; return false; } 77 | memset((void*)(((char*)data) + data_sz), 0, 4); 78 | fclose(f); 79 | 80 | // Compress 81 | int maxlen = data_sz + 512 + (data_sz >> 2) + sizeof(int); // total guess 82 | char* compressed = use_compression ? new char[maxlen] : data; 83 | int compressed_sz = use_compression ? stb_compress((stb_uchar*)compressed, (stb_uchar*)data, data_sz) : data_sz; 84 | if (use_compression) 85 | memset(compressed + compressed_sz, 0, maxlen - compressed_sz); 86 | 87 | // Output as Base85 encoded 88 | FILE* out = stdout; 89 | fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz); 90 | fprintf(out, "// Exported using binary_to_compressed_c.cpp\n"); 91 | const char* compressed_str = use_compression ? "compressed_" : ""; 92 | if (use_base85_encoding) 93 | { 94 | fprintf(out, "static const char %s_%sdata_base85[%d+1] =\n \"", symbol, compressed_str, (int)((compressed_sz+3)/4)*5); 95 | char prev_c = 0; 96 | for (int src_i = 0; src_i < compressed_sz; src_i += 4) 97 | { 98 | // This is made a little more complicated by the fact that ??X sequences are interpreted as trigraphs by old C/C++ compilers. So we need to escape pairs of ??. 99 | unsigned int d = *(unsigned int*)(compressed + src_i); 100 | for (unsigned int n5 = 0; n5 < 5; n5++, d /= 85) 101 | { 102 | char c = Encode85Byte(d); 103 | fprintf(out, (c == '?' && prev_c == '?') ? "\\%c" : "%c", c); 104 | prev_c = c; 105 | } 106 | if ((src_i % 112) == 112-4) 107 | fprintf(out, "\"\n \""); 108 | } 109 | fprintf(out, "\";\n\n"); 110 | } 111 | else 112 | { 113 | fprintf(out, "static const unsigned int %s_%ssize = %d;\n", symbol, compressed_str, (int)compressed_sz); 114 | fprintf(out, "static const unsigned int %s_%sdata[%d/4] =\n{", symbol, compressed_str, (int)((compressed_sz+3)/4)*4); 115 | int column = 0; 116 | for (int i = 0; i < compressed_sz; i += 4) 117 | { 118 | unsigned int d = *(unsigned int*)(compressed + i); 119 | if ((column++ % 12) == 0) 120 | fprintf(out, "\n 0x%08x, ", d); 121 | else 122 | fprintf(out, "0x%08x, ", d); 123 | } 124 | fprintf(out, "\n};\n\n"); 125 | } 126 | 127 | // Cleanup 128 | delete[] data; 129 | if (use_compression) 130 | delete[] compressed; 131 | return true; 132 | } 133 | 134 | // stb_compress* from stb.h - definition 135 | 136 | //////////////////// compressor /////////////////////// 137 | 138 | static stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen) 139 | { 140 | const unsigned long ADLER_MOD = 65521; 141 | unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; 142 | unsigned long blocklen, i; 143 | 144 | blocklen = buflen % 5552; 145 | while (buflen) { 146 | for (i=0; i + 7 < blocklen; i += 8) { 147 | s1 += buffer[0], s2 += s1; 148 | s1 += buffer[1], s2 += s1; 149 | s1 += buffer[2], s2 += s1; 150 | s1 += buffer[3], s2 += s1; 151 | s1 += buffer[4], s2 += s1; 152 | s1 += buffer[5], s2 += s1; 153 | s1 += buffer[6], s2 += s1; 154 | s1 += buffer[7], s2 += s1; 155 | 156 | buffer += 8; 157 | } 158 | 159 | for (; i < blocklen; ++i) 160 | s1 += *buffer++, s2 += s1; 161 | 162 | s1 %= ADLER_MOD, s2 %= ADLER_MOD; 163 | buflen -= blocklen; 164 | blocklen = 5552; 165 | } 166 | return (s2 << 16) + s1; 167 | } 168 | 169 | static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen) 170 | { 171 | stb_uint i; 172 | for (i=0; i < maxlen; ++i) 173 | if (m1[i] != m2[i]) return i; 174 | return i; 175 | } 176 | 177 | // simple implementation that just takes the source data in a big block 178 | 179 | static stb_uchar *stb__out; 180 | static FILE *stb__outfile; 181 | static stb_uint stb__outbytes; 182 | 183 | static void stb__write(unsigned char v) 184 | { 185 | fputc(v, stb__outfile); 186 | ++stb__outbytes; 187 | } 188 | 189 | //#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) 190 | #define stb_out(v) do { if (stb__out) *stb__out++ = (stb_uchar) (v); else stb__write((stb_uchar) (v)); } while (0) 191 | 192 | static void stb_out2(stb_uint v) { stb_out(v >> 8); stb_out(v); } 193 | static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); } 194 | static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); stb_out(v >> 8 ); stb_out(v); } 195 | 196 | static void outliterals(stb_uchar *in, int numlit) 197 | { 198 | while (numlit > 65536) { 199 | outliterals(in,65536); 200 | in += 65536; 201 | numlit -= 65536; 202 | } 203 | 204 | if (numlit == 0) ; 205 | else if (numlit <= 32) stb_out (0x000020 + numlit-1); 206 | else if (numlit <= 2048) stb_out2(0x000800 + numlit-1); 207 | else /* numlit <= 65536) */ stb_out3(0x070000 + numlit-1); 208 | 209 | if (stb__out) { 210 | memcpy(stb__out,in,numlit); 211 | stb__out += numlit; 212 | } else 213 | fwrite(in, 1, numlit, stb__outfile); 214 | } 215 | 216 | static int stb__window = 0x40000; // 256K 217 | 218 | static int stb_not_crap(int best, int dist) 219 | { 220 | return ((best > 2 && dist <= 0x00100) 221 | || (best > 5 && dist <= 0x04000) 222 | || (best > 7 && dist <= 0x80000)); 223 | } 224 | 225 | static stb_uint stb__hashsize = 32768; 226 | 227 | // note that you can play with the hashing functions all you 228 | // want without needing to change the decompressor 229 | #define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c]) 230 | #define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d]) 231 | #define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e]) 232 | 233 | static unsigned int stb__running_adler; 234 | 235 | static int stb_compress_chunk(stb_uchar *history, 236 | stb_uchar *start, 237 | stb_uchar *end, 238 | int length, 239 | int *pending_literals, 240 | stb_uchar **chash, 241 | stb_uint mask) 242 | { 243 | (void)history; 244 | int window = stb__window; 245 | stb_uint match_max; 246 | stb_uchar *lit_start = start - *pending_literals; 247 | stb_uchar *q = start; 248 | 249 | #define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask) 250 | 251 | // stop short of the end so we don't scan off the end doing 252 | // the hashing; this means we won't compress the last few bytes 253 | // unless they were part of something longer 254 | while (q < start+length && q+12 < end) { 255 | int m; 256 | stb_uint h1,h2,h3,h4, h; 257 | stb_uchar *t; 258 | int best = 2, dist=0; 259 | 260 | if (q+65536 > end) 261 | match_max = end-q; 262 | else 263 | match_max = 65536; 264 | 265 | #define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap(b,d))) 266 | 267 | #define STB__TRY(t,p) /* avoid retrying a match we already tried */ \ 268 | if (p ? dist != q-t : 1) \ 269 | if ((m = stb_matchlen(t, q, match_max)) > best) \ 270 | if (stb__nc(m,q-(t))) \ 271 | best = m, dist = q - (t) 272 | 273 | // rather than search for all matches, only try 4 candidate locations, 274 | // chosen based on 4 different hash functions of different lengths. 275 | // this strategy is inspired by LZO; hashing is unrolled here using the 276 | // 'hc' macro 277 | h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h); 278 | t = chash[h1]; if (t) STB__TRY(t,0); 279 | h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h); 280 | h = stb__hc2(q,h, 5, 6); t = chash[h2]; if (t) STB__TRY(t,1); 281 | h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h); 282 | h = stb__hc2(q,h, 9,10); t = chash[h3]; if (t) STB__TRY(t,1); 283 | h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h); 284 | t = chash[h4]; if (t) STB__TRY(t,1); 285 | 286 | // because we use a shared hash table, can only update it 287 | // _after_ we've probed all of them 288 | chash[h1] = chash[h2] = chash[h3] = chash[h4] = q; 289 | 290 | if (best > 2) 291 | assert(dist > 0); 292 | 293 | // see if our best match qualifies 294 | if (best < 3) { // fast path literals 295 | ++q; 296 | } else if (best > 2 && best <= 0x80 && dist <= 0x100) { 297 | outliterals(lit_start, q-lit_start); lit_start = (q += best); 298 | stb_out(0x80 + best-1); 299 | stb_out(dist-1); 300 | } else if (best > 5 && best <= 0x100 && dist <= 0x4000) { 301 | outliterals(lit_start, q-lit_start); lit_start = (q += best); 302 | stb_out2(0x4000 + dist-1); 303 | stb_out(best-1); 304 | } else if (best > 7 && best <= 0x100 && dist <= 0x80000) { 305 | outliterals(lit_start, q-lit_start); lit_start = (q += best); 306 | stb_out3(0x180000 + dist-1); 307 | stb_out(best-1); 308 | } else if (best > 8 && best <= 0x10000 && dist <= 0x80000) { 309 | outliterals(lit_start, q-lit_start); lit_start = (q += best); 310 | stb_out3(0x100000 + dist-1); 311 | stb_out2(best-1); 312 | } else if (best > 9 && dist <= 0x1000000) { 313 | if (best > 65536) best = 65536; 314 | outliterals(lit_start, q-lit_start); lit_start = (q += best); 315 | if (best <= 0x100) { 316 | stb_out(0x06); 317 | stb_out3(dist-1); 318 | stb_out(best-1); 319 | } else { 320 | stb_out(0x04); 321 | stb_out3(dist-1); 322 | stb_out2(best-1); 323 | } 324 | } else { // fallback literals if no match was a balanced tradeoff 325 | ++q; 326 | } 327 | } 328 | 329 | // if we didn't get all the way, add the rest to literals 330 | if (q-start < length) 331 | q = start+length; 332 | 333 | // the literals are everything from lit_start to q 334 | *pending_literals = (q - lit_start); 335 | 336 | stb__running_adler = stb_adler32(stb__running_adler, start, q - start); 337 | return q - start; 338 | } 339 | 340 | static int stb_compress_inner(stb_uchar *input, stb_uint length) 341 | { 342 | int literals = 0; 343 | stb_uint len,i; 344 | 345 | stb_uchar **chash; 346 | chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*)); 347 | if (chash == NULL) return 0; // failure 348 | for (i=0; i < stb__hashsize; ++i) 349 | chash[i] = NULL; 350 | 351 | // stream signature 352 | stb_out(0x57); stb_out(0xbc); 353 | stb_out2(0); 354 | 355 | stb_out4(0); // 64-bit length requires 32-bit leading 0 356 | stb_out4(length); 357 | stb_out4(stb__window); 358 | 359 | stb__running_adler = 1; 360 | 361 | len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1); 362 | assert(len == length); 363 | 364 | outliterals(input+length - literals, literals); 365 | 366 | free(chash); 367 | 368 | stb_out2(0x05fa); // end opcode 369 | 370 | stb_out4(stb__running_adler); 371 | 372 | return 1; // success 373 | } 374 | 375 | stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length) 376 | { 377 | stb__out = out; 378 | stb__outfile = NULL; 379 | 380 | stb_compress_inner(input, length); 381 | 382 | return stb__out - out; 383 | } 384 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/freetype/README.md: -------------------------------------------------------------------------------- 1 | # imgui_freetype 2 | 3 | Build font atlases using FreeType instead of stb_truetype (which is the default font rasterizer in Dear ImGui). 4 |
by @vuhdo, @mikesart, @ocornut. 5 | 6 | ### Usage 7 | 8 | 1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype`). 9 | 2. Add imgui_freetype.h/cpp alongside your imgui sources. 10 | 3. Include imgui_freetype.h after imgui.h. 11 | 4. Call `ImGuiFreeType::BuildFontAtlas()` *BEFORE* calling `ImFontAtlas::GetTexDataAsRGBA32()` or `ImFontAtlas::Build()` (so normal Build() won't be called): 12 | 13 | ```cpp 14 | // See ImGuiFreeType::RasterizationFlags 15 | unsigned int flags = ImGuiFreeType::NoHinting; 16 | ImGuiFreeType::BuildFontAtlas(io.Fonts, flags); 17 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 18 | ``` 19 | 20 | ### Gamma Correct Blending 21 | 22 | FreeType assumes blending in linear space rather than gamma space. 23 | See FreeType note for [FT_Render_Glyph](https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph). 24 | For correct results you need to be using sRGB and convert to linear space in the pixel shader output. 25 | The default Dear ImGui styles will be impacted by this change (alpha values will need tweaking). 26 | 27 | ### Test code Usage 28 | ```cpp 29 | #include "misc/freetype/imgui_freetype.h" 30 | #include "misc/freetype/imgui_freetype.cpp" 31 | 32 | // Load various small fonts 33 | ImGuiIO& io = ImGui::GetIO(); 34 | io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 13.0f); 35 | io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 13.0f); 36 | io.Fonts->AddFontDefault(); 37 | 38 | FreeTypeTest freetype_test; 39 | 40 | // Main Loop 41 | while (true) 42 | { 43 | if (freetype_test.UpdateRebuild()) 44 | { 45 | // REUPLOAD FONT TEXTURE TO GPU 46 | ImGui_ImplXXX_DestroyDeviceObjects(); 47 | ImGui_ImplXXX_CreateDeviceObjects(); 48 | } 49 | ImGui::NewFrame(); 50 | freetype_test.ShowFreetypeOptionsWindow(); 51 | ... 52 | } 53 | ``` 54 | 55 | ### Test code 56 | ```cpp 57 | #include "misc/freetype/imgui_freetype.h" 58 | #include "misc/freetype/imgui_freetype.cpp" 59 | 60 | struct FreeTypeTest 61 | { 62 | enum FontBuildMode 63 | { 64 | FontBuildMode_FreeType, 65 | FontBuildMode_Stb 66 | }; 67 | 68 | FontBuildMode BuildMode; 69 | bool WantRebuild; 70 | float FontsMultiply; 71 | int FontsPadding; 72 | unsigned int FontsFlags; 73 | 74 | FreeTypeTest() 75 | { 76 | BuildMode = FontBuildMode_FreeType; 77 | WantRebuild = true; 78 | FontsMultiply = 1.0f; 79 | FontsPadding = 1; 80 | FontsFlags = 0; 81 | } 82 | 83 | // Call _BEFORE_ NewFrame() 84 | bool UpdateRebuild() 85 | { 86 | if (!WantRebuild) 87 | return false; 88 | ImGuiIO& io = ImGui::GetIO(); 89 | io.Fonts->TexGlyphPadding = FontsPadding; 90 | for (int n = 0; n < io.Fonts->ConfigData.Size; n++) 91 | { 92 | ImFontConfig* font_config = (ImFontConfig*)&io.Fonts->ConfigData[n]; 93 | font_config->RasterizerMultiply = FontsMultiply; 94 | font_config->RasterizerFlags = (BuildMode == FontBuildMode_FreeType) ? FontsFlags : 0x00; 95 | } 96 | if (BuildMode == FontBuildMode_FreeType) 97 | ImGuiFreeType::BuildFontAtlas(io.Fonts, FontsFlags); 98 | else if (BuildMode == FontBuildMode_Stb) 99 | io.Fonts->Build(); 100 | WantRebuild = false; 101 | return true; 102 | } 103 | 104 | // Call to draw interface 105 | void ShowFreetypeOptionsWindow() 106 | { 107 | ImGui::Begin("FreeType Options"); 108 | ImGui::ShowFontSelector("Fonts"); 109 | WantRebuild |= ImGui::RadioButton("FreeType", (int*)&BuildMode, FontBuildMode_FreeType); 110 | ImGui::SameLine(); 111 | WantRebuild |= ImGui::RadioButton("Stb (Default)", (int*)&BuildMode, FontBuildMode_Stb); 112 | WantRebuild |= ImGui::DragFloat("Multiply", &FontsMultiply, 0.001f, 0.0f, 2.0f); 113 | WantRebuild |= ImGui::DragInt("Padding", &FontsPadding, 0.1f, 0, 16); 114 | if (BuildMode == FontBuildMode_FreeType) 115 | { 116 | WantRebuild |= ImGui::CheckboxFlags("NoHinting", &FontsFlags, ImGuiFreeType::NoHinting); 117 | WantRebuild |= ImGui::CheckboxFlags("NoAutoHint", &FontsFlags, ImGuiFreeType::NoAutoHint); 118 | WantRebuild |= ImGui::CheckboxFlags("ForceAutoHint", &FontsFlags, ImGuiFreeType::ForceAutoHint); 119 | WantRebuild |= ImGui::CheckboxFlags("LightHinting", &FontsFlags, ImGuiFreeType::LightHinting); 120 | WantRebuild |= ImGui::CheckboxFlags("MonoHinting", &FontsFlags, ImGuiFreeType::MonoHinting); 121 | WantRebuild |= ImGui::CheckboxFlags("Bold", &FontsFlags, ImGuiFreeType::Bold); 122 | WantRebuild |= ImGui::CheckboxFlags("Oblique", &FontsFlags, ImGuiFreeType::Oblique); 123 | WantRebuild |= ImGui::CheckboxFlags("Monochrome", &FontsFlags, ImGuiFreeType::Monochrome); 124 | } 125 | ImGui::End(); 126 | } 127 | }; 128 | ``` 129 | 130 | ### Known issues 131 | - `cfg.OversampleH`, `OversampleV` are ignored (but perhaps not so necessary with this rasterizer). 132 | 133 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/freetype/imgui_freetype.cpp: -------------------------------------------------------------------------------- 1 | // Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui 2 | // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype 3 | // Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained and v0.60+ by @ocornut. 4 | 5 | // Changelog: 6 | // - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks. 7 | // - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply. 8 | // - v0.52: (2017/09/26) fixes for imgui internal changes. 9 | // - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement). 10 | // - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member. 11 | // - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club) 12 | // - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX. 13 | // - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. 14 | // - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions(). 15 | // - v0.62: (2019/02/09) added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!) 16 | 17 | // Gamma Correct Blending: 18 | // FreeType assumes blending in linear space rather than gamma space. 19 | // See https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph 20 | // For correct results you need to be using sRGB and convert to linear space in the pixel shader output. 21 | // The default imgui styles will be impacted by this change (alpha values will need tweaking). 22 | 23 | // FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). 24 | 25 | #include "imgui_freetype.h" 26 | #include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*, 27 | #include 28 | #include 29 | #include FT_FREETYPE_H // 30 | #include FT_MODULE_H // 31 | #include FT_GLYPH_H // 32 | #include FT_SYNTHESIS_H // 33 | 34 | #ifdef _MSC_VER 35 | #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) 36 | #endif 37 | 38 | #if defined(__GNUC__) 39 | #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 40 | #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used 41 | #endif 42 | 43 | namespace 44 | { 45 | // Glyph metrics: 46 | // -------------- 47 | // 48 | // xmin xmax 49 | // | | 50 | // |<-------- width -------->| 51 | // | | 52 | // | +-------------------------+----------------- ymax 53 | // | | ggggggggg ggggg | ^ ^ 54 | // | | g:::::::::ggg::::g | | | 55 | // | | g:::::::::::::::::g | | | 56 | // | | g::::::ggggg::::::gg | | | 57 | // | | g:::::g g:::::g | | | 58 | // offsetX -|-------->| g:::::g g:::::g | offsetY | 59 | // | | g:::::g g:::::g | | | 60 | // | | g::::::g g:::::g | | | 61 | // | | g:::::::ggggg:::::g | | | 62 | // | | g::::::::::::::::g | | height 63 | // | | gg::::::::::::::g | | | 64 | // baseline ---*---------|---- gggggggg::::::g-----*-------- | 65 | // / | | g:::::g | | 66 | // origin | | gggggg g:::::g | | 67 | // | | g:::::gg gg:::::g | | 68 | // | | g::::::ggg:::::::g | | 69 | // | | gg:::::::::::::g | | 70 | // | | ggg::::::ggg | | 71 | // | | gggggg | v 72 | // | +-------------------------+----------------- ymin 73 | // | | 74 | // |------------- advanceX ----------->| 75 | 76 | /// A structure that describe a glyph. 77 | struct GlyphInfo 78 | { 79 | int Width; // Glyph's width in pixels. 80 | int Height; // Glyph's height in pixels. 81 | FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph. 82 | FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0. 83 | float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0. 84 | }; 85 | 86 | // Font parameters and metrics. 87 | struct FontInfo 88 | { 89 | uint32_t PixelHeight; // Size this font was generated with. 90 | float Ascender; // The pixel extents above the baseline in pixels (typically positive). 91 | float Descender; // The extents below the baseline in pixels (typically negative). 92 | float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. 93 | float LineGap; // The spacing in pixels between one row's descent and the next row's ascent. 94 | float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font. 95 | }; 96 | 97 | // FreeType glyph rasterizer. 98 | // NB: No ctor/dtor, explicitly call Init()/Shutdown() 99 | struct FreeTypeFont 100 | { 101 | bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. 102 | void CloseFont(); 103 | void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size 104 | const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); 105 | const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); 106 | void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); 107 | ~FreeTypeFont() { CloseFont(); } 108 | 109 | // [Internals] 110 | FontInfo Info; // Font descriptor of the current font. 111 | FT_Face Face; 112 | unsigned int UserFlags; // = ImFontConfig::RasterizerFlags 113 | FT_Int32 LoadFlags; 114 | FT_Render_Mode RenderMode; 115 | }; 116 | 117 | // From SDL_ttf: Handy routines for converting from fixed point 118 | #define FT_CEIL(X) (((X + 63) & -64) / 64) 119 | 120 | bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags) 121 | { 122 | FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); 123 | if (error != 0) 124 | return false; 125 | error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE); 126 | if (error != 0) 127 | return false; 128 | 129 | memset(&Info, 0, sizeof(Info)); 130 | SetPixelHeight((uint32_t)cfg.SizePixels); 131 | 132 | // Convert to FreeType flags (NB: Bold and Oblique are processed separately) 133 | UserFlags = cfg.RasterizerFlags | extra_user_flags; 134 | LoadFlags = FT_LOAD_NO_BITMAP; 135 | if (UserFlags & ImGuiFreeType::NoHinting) 136 | LoadFlags |= FT_LOAD_NO_HINTING; 137 | if (UserFlags & ImGuiFreeType::NoAutoHint) 138 | LoadFlags |= FT_LOAD_NO_AUTOHINT; 139 | if (UserFlags & ImGuiFreeType::ForceAutoHint) 140 | LoadFlags |= FT_LOAD_FORCE_AUTOHINT; 141 | if (UserFlags & ImGuiFreeType::LightHinting) 142 | LoadFlags |= FT_LOAD_TARGET_LIGHT; 143 | else if (UserFlags & ImGuiFreeType::MonoHinting) 144 | LoadFlags |= FT_LOAD_TARGET_MONO; 145 | else 146 | LoadFlags |= FT_LOAD_TARGET_NORMAL; 147 | 148 | if (UserFlags & ImGuiFreeType::Monochrome) 149 | RenderMode = FT_RENDER_MODE_MONO; 150 | else 151 | RenderMode = FT_RENDER_MODE_NORMAL; 152 | 153 | return true; 154 | } 155 | 156 | void FreeTypeFont::CloseFont() 157 | { 158 | if (Face) 159 | { 160 | FT_Done_Face(Face); 161 | Face = NULL; 162 | } 163 | } 164 | 165 | void FreeTypeFont::SetPixelHeight(int pixel_height) 166 | { 167 | // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' 168 | // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. 169 | // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result. 170 | FT_Size_RequestRec req; 171 | req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; 172 | req.width = 0; 173 | req.height = (uint32_t)pixel_height * 64; 174 | req.horiResolution = 0; 175 | req.vertResolution = 0; 176 | FT_Request_Size(Face, &req); 177 | 178 | // Update font info 179 | FT_Size_Metrics metrics = Face->size->metrics; 180 | Info.PixelHeight = (uint32_t)pixel_height; 181 | Info.Ascender = (float)FT_CEIL(metrics.ascender); 182 | Info.Descender = (float)FT_CEIL(metrics.descender); 183 | Info.LineSpacing = (float)FT_CEIL(metrics.height); 184 | Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender); 185 | Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance); 186 | } 187 | 188 | const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint) 189 | { 190 | uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint); 191 | if (glyph_index == 0) 192 | return NULL; 193 | FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags); 194 | if (error) 195 | return NULL; 196 | 197 | // Need an outline for this to work 198 | FT_GlyphSlot slot = Face->glyph; 199 | IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE); 200 | 201 | // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) 202 | if (UserFlags & ImGuiFreeType::Bold) 203 | FT_GlyphSlot_Embolden(slot); 204 | if (UserFlags & ImGuiFreeType::Oblique) 205 | { 206 | FT_GlyphSlot_Oblique(slot); 207 | //FT_BBox bbox; 208 | //FT_Outline_Get_BBox(&slot->outline, &bbox); 209 | //slot->metrics.width = bbox.xMax - bbox.xMin; 210 | //slot->metrics.height = bbox.yMax - bbox.yMin; 211 | } 212 | 213 | return &slot->metrics; 214 | } 215 | 216 | const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) 217 | { 218 | FT_GlyphSlot slot = Face->glyph; 219 | FT_Error error = FT_Render_Glyph(slot, RenderMode); 220 | if (error != 0) 221 | return NULL; 222 | 223 | FT_Bitmap* ft_bitmap = &Face->glyph->bitmap; 224 | out_glyph_info->Width = (int)ft_bitmap->width; 225 | out_glyph_info->Height = (int)ft_bitmap->rows; 226 | out_glyph_info->OffsetX = Face->glyph->bitmap_left; 227 | out_glyph_info->OffsetY = -Face->glyph->bitmap_top; 228 | out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x); 229 | 230 | return ft_bitmap; 231 | } 232 | 233 | void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) 234 | { 235 | IM_ASSERT(ft_bitmap != NULL); 236 | const uint32_t w = ft_bitmap->width; 237 | const uint32_t h = ft_bitmap->rows; 238 | const uint8_t* src = ft_bitmap->buffer; 239 | const uint32_t src_pitch = ft_bitmap->pitch; 240 | 241 | switch (ft_bitmap->pixel_mode) 242 | { 243 | case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel. 244 | { 245 | if (multiply_table == NULL) 246 | { 247 | for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) 248 | memcpy(dst, src, w); 249 | } 250 | else 251 | { 252 | for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) 253 | for (uint32_t x = 0; x < w; x++) 254 | dst[x] = multiply_table[src[x]]; 255 | } 256 | break; 257 | } 258 | case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB. 259 | { 260 | uint8_t color0 = multiply_table ? multiply_table[0] : 0; 261 | uint8_t color1 = multiply_table ? multiply_table[255] : 255; 262 | for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) 263 | { 264 | uint8_t bits = 0; 265 | const uint8_t* bits_ptr = src; 266 | for (uint32_t x = 0; x < w; x++, bits <<= 1) 267 | { 268 | if ((x & 7) == 0) 269 | bits = *bits_ptr++; 270 | dst[x] = (bits & 0x80) ? color1 : color0; 271 | } 272 | } 273 | break; 274 | } 275 | default: 276 | IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); 277 | } 278 | } 279 | } 280 | 281 | #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) 282 | #define STBRP_ASSERT(x) IM_ASSERT(x) 283 | #define STBRP_STATIC 284 | #define STB_RECT_PACK_IMPLEMENTATION 285 | #include "imstb_rectpack.h" 286 | #endif 287 | 288 | struct ImFontBuildSrcGlyphFT 289 | { 290 | GlyphInfo Info; 291 | uint32_t Codepoint; 292 | unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array 293 | }; 294 | 295 | struct ImFontBuildSrcDataFT 296 | { 297 | FreeTypeFont Font; 298 | stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. 299 | const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) 300 | int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] 301 | int GlyphsHighest; // Highest requested codepoint 302 | int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) 303 | ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) 304 | ImVector GlyphsList; 305 | }; 306 | 307 | // Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) 308 | struct ImFontBuildDstDataFT 309 | { 310 | int SrcCount; // Number of source fonts targeting this destination font. 311 | int GlyphsHighest; 312 | int GlyphsCount; 313 | ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. 314 | }; 315 | 316 | bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags) 317 | { 318 | IM_ASSERT(atlas->ConfigData.Size > 0); 319 | 320 | ImFontAtlasBuildRegisterDefaultCustomRects(atlas); 321 | 322 | // Clear atlas 323 | atlas->TexID = (ImTextureID)NULL; 324 | atlas->TexWidth = atlas->TexHeight = 0; 325 | atlas->TexUvScale = ImVec2(0.0f, 0.0f); 326 | atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); 327 | atlas->ClearTexData(); 328 | 329 | // Temporary storage for building 330 | ImVector src_tmp_array; 331 | ImVector dst_tmp_array; 332 | src_tmp_array.resize(atlas->ConfigData.Size); 333 | dst_tmp_array.resize(atlas->Fonts.Size); 334 | memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); 335 | memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); 336 | 337 | // 1. Initialize font loading structure, check font data validity 338 | for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) 339 | { 340 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 341 | ImFontConfig& cfg = atlas->ConfigData[src_i]; 342 | FreeTypeFont& font_face = src_tmp.Font; 343 | IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); 344 | 345 | // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) 346 | src_tmp.DstIndex = -1; 347 | for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) 348 | if (cfg.DstFont == atlas->Fonts[output_i]) 349 | src_tmp.DstIndex = output_i; 350 | IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? 351 | if (src_tmp.DstIndex == -1) 352 | return false; 353 | 354 | // Load font 355 | if (!font_face.InitFont(ft_library, cfg, extra_flags)) 356 | return false; 357 | 358 | // Measure highest codepoints 359 | ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; 360 | src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); 361 | for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) 362 | src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); 363 | dst_tmp.SrcCount++; 364 | dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); 365 | } 366 | 367 | // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. 368 | int total_glyphs_count = 0; 369 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 370 | { 371 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 372 | ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; 373 | src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); 374 | if (dst_tmp.GlyphsSet.Storage.empty()) 375 | dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); 376 | 377 | for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) 378 | for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) 379 | { 380 | if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) 381 | continue; 382 | uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..) 383 | if (glyph_index == 0) 384 | continue; 385 | 386 | // Add to avail set/counters 387 | src_tmp.GlyphsCount++; 388 | dst_tmp.GlyphsCount++; 389 | src_tmp.GlyphsSet.SetBit(codepoint, true); 390 | dst_tmp.GlyphsSet.SetBit(codepoint, true); 391 | total_glyphs_count++; 392 | } 393 | } 394 | 395 | // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) 396 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 397 | { 398 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 399 | src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); 400 | 401 | IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(int)); 402 | const int* it_begin = src_tmp.GlyphsSet.Storage.begin(); 403 | const int* it_end = src_tmp.GlyphsSet.Storage.end(); 404 | for (const int* it = it_begin; it < it_end; it++) 405 | if (int entries_32 = *it) 406 | for (int bit_n = 0; bit_n < 32; bit_n++) 407 | if (entries_32 & (1 << bit_n)) 408 | { 409 | ImFontBuildSrcGlyphFT src_glyph; 410 | memset(&src_glyph, 0, sizeof(src_glyph)); 411 | src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n); 412 | //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it.. 413 | src_tmp.GlyphsList.push_back(src_glyph); 414 | } 415 | src_tmp.GlyphsSet.Clear(); 416 | IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); 417 | } 418 | for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) 419 | dst_tmp_array[dst_i].GlyphsSet.Clear(); 420 | dst_tmp_array.clear(); 421 | 422 | // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) 423 | // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) 424 | ImVector buf_rects; 425 | buf_rects.resize(total_glyphs_count); 426 | memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); 427 | 428 | // Allocate temporary rasterization data buffers. 429 | // We could not find a way to retrieve accurate glyph size without rendering them. 430 | // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform) 431 | // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations. 432 | const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024; 433 | int buf_bitmap_current_used_bytes = 0; 434 | ImVector buf_bitmap_buffers; 435 | buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); 436 | 437 | // 4. Gather glyphs sizes so we can pack them in our virtual canvas. 438 | // 8. Render/rasterize font characters into the texture 439 | int total_surface = 0; 440 | int buf_rects_out_n = 0; 441 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 442 | { 443 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 444 | ImFontConfig& cfg = atlas->ConfigData[src_i]; 445 | if (src_tmp.GlyphsCount == 0) 446 | continue; 447 | 448 | src_tmp.Rects = &buf_rects[buf_rects_out_n]; 449 | buf_rects_out_n += src_tmp.GlyphsCount; 450 | 451 | // Compute multiply table if requested 452 | const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f); 453 | unsigned char multiply_table[256]; 454 | if (multiply_enabled) 455 | ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); 456 | 457 | // Gather the sizes of all rectangles we will need to pack 458 | const int padding = atlas->TexGlyphPadding; 459 | for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) 460 | { 461 | ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; 462 | 463 | const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint); 464 | IM_ASSERT(metrics != NULL); 465 | if (metrics == NULL) 466 | continue; 467 | 468 | // Render glyph into a bitmap (currently held by FreeType) 469 | const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info); 470 | IM_ASSERT(ft_bitmap); 471 | 472 | // Allocate new temporary chunk if needed 473 | const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height; 474 | if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE) 475 | { 476 | buf_bitmap_current_used_bytes = 0; 477 | buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); 478 | } 479 | 480 | // Blit rasterized pixels to our temporary buffer and keep a pointer to it. 481 | src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes; 482 | buf_bitmap_current_used_bytes += bitmap_size_in_bytes; 483 | src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL); 484 | 485 | src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding); 486 | src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding); 487 | total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; 488 | } 489 | } 490 | 491 | // We need a width for the skyline algorithm, any width! 492 | // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. 493 | // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. 494 | const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; 495 | atlas->TexHeight = 0; 496 | if (atlas->TexDesiredWidth > 0) 497 | atlas->TexWidth = atlas->TexDesiredWidth; 498 | else 499 | atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; 500 | 501 | // 5. Start packing 502 | // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). 503 | const int TEX_HEIGHT_MAX = 1024 * 32; 504 | const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding; 505 | ImVector pack_nodes; 506 | pack_nodes.resize(num_nodes_for_packing_algorithm); 507 | stbrp_context pack_context; 508 | stbrp_init_target(&pack_context, atlas->TexWidth, TEX_HEIGHT_MAX, pack_nodes.Data, pack_nodes.Size); 509 | ImFontAtlasBuildPackCustomRects(atlas, &pack_context); 510 | 511 | // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. 512 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 513 | { 514 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 515 | if (src_tmp.GlyphsCount == 0) 516 | continue; 517 | 518 | stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount); 519 | 520 | // Extend texture height and mark missing glyphs as non-packed so we won't render them. 521 | // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) 522 | for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) 523 | if (src_tmp.Rects[glyph_i].was_packed) 524 | atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); 525 | } 526 | 527 | // 7. Allocate texture 528 | atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); 529 | atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); 530 | atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); 531 | memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); 532 | 533 | // 8. Copy rasterized font characters back into the main texture 534 | // 9. Setup ImFont and glyphs for runtime 535 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 536 | { 537 | ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; 538 | if (src_tmp.GlyphsCount == 0) 539 | continue; 540 | 541 | ImFontConfig& cfg = atlas->ConfigData[src_i]; 542 | ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) 543 | 544 | const float ascent = src_tmp.Font.Info.Ascender; 545 | const float descent = src_tmp.Font.Info.Descender; 546 | ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); 547 | const float font_off_x = cfg.GlyphOffset.x; 548 | const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); 549 | 550 | const int padding = atlas->TexGlyphPadding; 551 | for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) 552 | { 553 | ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; 554 | stbrp_rect& pack_rect = src_tmp.Rects[glyph_i]; 555 | IM_ASSERT(pack_rect.was_packed); 556 | 557 | GlyphInfo& info = src_glyph.Info; 558 | IM_ASSERT(info.Width + padding <= pack_rect.w); 559 | IM_ASSERT(info.Height + padding <= pack_rect.h); 560 | const int tx = pack_rect.x + padding; 561 | const int ty = pack_rect.y + padding; 562 | 563 | // Blit from temporary buffer to final texture 564 | size_t blit_src_stride = (size_t)src_glyph.Info.Width; 565 | size_t blit_dst_stride = (size_t)atlas->TexWidth; 566 | unsigned char* blit_src = src_glyph.BitmapData; 567 | unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx; 568 | for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride) 569 | memcpy(blit_dst, blit_src, blit_src_stride); 570 | 571 | float char_advance_x_org = info.AdvanceX; 572 | float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); 573 | float char_off_x = font_off_x; 574 | if (char_advance_x_org != char_advance_x_mod) 575 | char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; 576 | 577 | // Register glyph 578 | float x0 = info.OffsetX + char_off_x; 579 | float y0 = info.OffsetY + font_off_y; 580 | float x1 = x0 + info.Width; 581 | float y1 = y0 + info.Height; 582 | float u0 = (tx) / (float)atlas->TexWidth; 583 | float v0 = (ty) / (float)atlas->TexHeight; 584 | float u1 = (tx + info.Width) / (float)atlas->TexWidth; 585 | float v1 = (ty + info.Height) / (float)atlas->TexHeight; 586 | dst_font->AddGlyph((ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, char_advance_x_mod); 587 | } 588 | 589 | src_tmp.Rects = NULL; 590 | } 591 | 592 | // Cleanup 593 | for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++) 594 | IM_FREE(buf_bitmap_buffers[buf_i]); 595 | for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) 596 | src_tmp_array[src_i].~ImFontBuildSrcDataFT(); 597 | 598 | ImFontAtlasBuildFinish(atlas); 599 | 600 | return true; 601 | } 602 | 603 | // Default memory allocators 604 | static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); } 605 | static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); } 606 | 607 | // Current memory allocators 608 | static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; 609 | static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc; 610 | static void* GImFreeTypeAllocatorUserData = NULL; 611 | 612 | // FreeType memory allocation callbacks 613 | static void* FreeType_Alloc(FT_Memory /*memory*/, long size) 614 | { 615 | return GImFreeTypeAllocFunc((size_t)size, GImFreeTypeAllocatorUserData); 616 | } 617 | 618 | static void FreeType_Free(FT_Memory /*memory*/, void* block) 619 | { 620 | GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); 621 | } 622 | 623 | static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block) 624 | { 625 | // Implement realloc() as we don't ask user to provide it. 626 | if (block == NULL) 627 | return GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData); 628 | 629 | if (new_size == 0) 630 | { 631 | GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); 632 | return NULL; 633 | } 634 | 635 | if (new_size > cur_size) 636 | { 637 | void* new_block = GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData); 638 | memcpy(new_block, block, (size_t)cur_size); 639 | GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); 640 | return new_block; 641 | } 642 | 643 | return block; 644 | } 645 | 646 | bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) 647 | { 648 | // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html 649 | FT_MemoryRec_ memory_rec = {}; 650 | memory_rec.user = NULL; 651 | memory_rec.alloc = &FreeType_Alloc; 652 | memory_rec.free = &FreeType_Free; 653 | memory_rec.realloc = &FreeType_Realloc; 654 | 655 | // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library 656 | FT_Library ft_library; 657 | FT_Error error = FT_New_Library(&memory_rec, &ft_library); 658 | if (error != 0) 659 | return false; 660 | 661 | // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. 662 | FT_Add_Default_Modules(ft_library); 663 | 664 | bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); 665 | FT_Done_Library(ft_library); 666 | 667 | return ret; 668 | } 669 | 670 | void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) 671 | { 672 | GImFreeTypeAllocFunc = alloc_func; 673 | GImFreeTypeFreeFunc = free_func; 674 | GImFreeTypeAllocatorUserData = user_data; 675 | } 676 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/freetype/imgui_freetype.h: -------------------------------------------------------------------------------- 1 | // Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui 2 | // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype 3 | // Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut 4 | 5 | #pragma once 6 | 7 | #include "imgui.h" // IMGUI_API, ImFontAtlas 8 | 9 | namespace ImGuiFreeType 10 | { 11 | // Hinting greatly impacts visuals (and glyph sizes). 12 | // When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output. 13 | // The Default hinting mode usually looks good, but may distort glyphs in an unusual way. 14 | // The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. 15 | 16 | // You can set those flags on a per font basis in ImFontConfig::RasterizerFlags. 17 | // Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts. 18 | enum RasterizerFlags 19 | { 20 | // By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. 21 | NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. 22 | NoAutoHint = 1 << 1, // Disable auto-hinter. 23 | ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. 24 | LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. 25 | MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. 26 | Bold = 1 << 5, // Styling: Should we artificially embolden the font? 27 | Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? 28 | Monochrome = 1 << 7 // Disable anti-aliasing. Combine this with MonoHinting for best results! 29 | }; 30 | 31 | IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); 32 | 33 | // By default ImGuiFreeType will use IM_ALLOC()/IM_FREE(). 34 | // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired: 35 | IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); 36 | } 37 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/natvis/README.txt: -------------------------------------------------------------------------------- 1 | 2 | Natvis file to describe dear imgui types in the Visual Studio debugger. 3 | With this, types like ImVector<> will be displayed nicely in the debugger. 4 | You can include this file a Visual Studio project file, or install it in Visual Studio folder. 5 | -------------------------------------------------------------------------------- /code/cimgui/imgui/misc/natvis/imgui.natvis: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{Size={Size} Capacity={Capacity}}} 9 | 10 | 11 | Size 12 | Data 13 | 14 | 15 | 16 | 17 | 18 | {{x={x,g} y={y,g}}} 19 | 20 | 21 | 22 | {{x={x,g} y={y,g} z={z,g} w={w,g}}} 23 | 24 | 25 | 26 | {{Min=({Min.x,g} {Min.y,g}) Max=({Max.x,g} {Max.y,g}) Size=({Max.x-Min.x,g} {Max.y-Min.y,g})}} 27 | 28 | Min 29 | Max 30 | Max.x - Min.x 31 | Max.y - Min.y 32 | 33 | 34 | 35 | 36 | {{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}} 37 | 38 | 39 | -------------------------------------------------------------------------------- /code/common.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const Allocator = std.mem.Allocator; 3 | 4 | // NOTE(hugo): The stretchy_buffer and hashmap types 5 | // are directly taken from Per Vogsen's Bitwise project ! 6 | 7 | pub fn stretchy_buffer(comptime T: type) type { 8 | return struct { 9 | allocator: *Allocator, 10 | len: usize, 11 | elems: []T, 12 | 13 | const Self = @This(); 14 | 15 | pub fn init(allocator: *Allocator) Self { 16 | return Self{ 17 | .allocator = allocator, 18 | .len = 0, 19 | .elems = [_]T{}, 20 | }; 21 | } 22 | 23 | pub fn push(buf: *Self, elem: T) !void { 24 | try fit(buf, 1 + buf.len); 25 | buf.elems[buf.len] = elem; 26 | buf.len += 1; 27 | } 28 | 29 | pub fn append(buf: *Self, elems: []const T) !void { 30 | for (elems) |e| try buf.push(e); 31 | } 32 | 33 | fn fit(buf: *Self, n: usize) !void { 34 | if (n > buf.elems.len) { 35 | try grow(buf, n); 36 | } 37 | } 38 | 39 | fn grow(buf: *Self, new_len: usize) !void { 40 | const new_cap = std.math.max(2 * buf.elems.len, std.math.min(new_len, 16)); 41 | if (buf.elems.len == 0) { 42 | buf.elems = try buf.allocator.alloc(T, new_cap); 43 | } else { 44 | buf.elems = try buf.allocator.realloc(buf.elems, new_cap); 45 | } 46 | } 47 | 48 | pub fn clear(buf: *Self) void { 49 | buf.len = 0; 50 | } 51 | 52 | pub fn free(buf: *Self) void { 53 | buf.allocator.free(buf.elems); 54 | } 55 | 56 | pub fn elements(buf: *Self) []T { 57 | return buf.elems[0..buf.len]; 58 | } 59 | }; 60 | } 61 | 62 | test "init" { 63 | var buf = stretchy_buffer(i32).init(&std.heap.DirectAllocator.init().allocator); 64 | std.debug.assert(buf.len == 0); 65 | std.debug.assert(buf.elems.len == 0); 66 | } 67 | 68 | test "push i32" { 69 | var buf = stretchy_buffer(i32).init(&std.heap.DirectAllocator.init().allocator); 70 | try buf.push(1); 71 | try buf.push(2); 72 | try buf.push(5); 73 | for (buf.elements()) |e| { 74 | std.debug.warn("{}\n", e); 75 | } 76 | buf.clear(); 77 | std.debug.assert(buf.len == 0); 78 | } 79 | 80 | test "push struct" { 81 | const myStruct = struct { 82 | a: i32, 83 | b: bool, 84 | }; 85 | 86 | const A = myStruct{ 87 | .a = 0, 88 | .b = true, 89 | }; 90 | 91 | const B = myStruct{ 92 | .a = 1, 93 | .b = false, 94 | }; 95 | 96 | var buf = stretchy_buffer(myStruct).init(&std.heap.DirectAllocator.init().allocator); 97 | try buf.push(A); 98 | try buf.push(B); 99 | for (buf.elements()) |e| { 100 | std.debug.warn("{}\n", e); 101 | } 102 | } 103 | 104 | pub fn hashmap(comptime V: type) type { 105 | return struct { 106 | values: []V, 107 | keys: []?u64, 108 | len: usize, 109 | allocator: *Allocator, 110 | 111 | const Self = @This(); 112 | 113 | pub fn init(allocator: *Allocator) Self { 114 | return Self{ 115 | .values = []align(@alignOf(V)) V{}, 116 | .keys = []align(@alignOf(?u64)) ?u64{}, 117 | .len = 0, 118 | .allocator = allocator, 119 | }; 120 | } 121 | 122 | pub fn get(map: *Self, key: u64) ?V { 123 | if (map.len == 0) { 124 | return null; 125 | } 126 | var i = hash(key); 127 | while (true) { 128 | i &= map.values.len - 1; 129 | if (map.keys[i] == null) { 130 | return null; 131 | } else if (map.keys[i].? == key) { 132 | return map.values[i]; 133 | } 134 | i += 1; 135 | } 136 | } 137 | 138 | pub fn put(map: *Self, key: u64, value: V) !void { 139 | if (2 * map.len >= map.values.len) { 140 | try map.grow(2 * map.values.len); 141 | } 142 | var i: u64 = hash(key); 143 | while (true) { 144 | i &= map.values.len - 1; 145 | if (map.keys[i] == null) { 146 | map.len += 1; 147 | map.keys[i] = key; 148 | map.values[i] = value; 149 | return; 150 | } else if (map.keys[i].? == key) { 151 | map.values[i] = value; 152 | } 153 | i += 1; 154 | } 155 | } 156 | 157 | fn grow(map: *Self, new_cap: usize) !void { 158 | var cap = std.math.max(new_cap, 16); 159 | var new_map = Self{ 160 | .allocator = map.allocator, 161 | .values = try map.allocator.alloc(V, cap), 162 | .keys = try map.allocator.alloc(?u64, cap), 163 | .len = map.len, 164 | }; 165 | 166 | for (new_map.keys) |*k| { 167 | k.* = null; 168 | } 169 | 170 | for (map.values) |v, i| { 171 | if (map.keys[i]) |k| { 172 | new_map.put(k, v) catch unreachable; 173 | } 174 | } 175 | 176 | map.allocator.free(map.values); 177 | map.allocator.free(map.keys); 178 | map.* = new_map; 179 | } 180 | 181 | fn hash(x: u64) u64 { 182 | var result: u64 = undefined; 183 | _ = @mulWithOverflow(u64, x, 0xff51afd7ed558ccd, &result); 184 | result ^= result >> 32; 185 | return result; 186 | } 187 | }; 188 | } 189 | 190 | test "hash test" { 191 | var map = hashmap(u64).init(&std.heap.DirectAllocator.init().allocator); 192 | var i: u64 = 1; 193 | while (i < 1024) : (i += 1) { 194 | try map.put(i, i + 1); 195 | } 196 | 197 | i = 1; 198 | while (i < 1024) : (i += 1) { 199 | if (map.get(i)) |v| { 200 | std.debug.assert(v == i + 1); 201 | } else { 202 | unreachable; 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /code/compile_cimgui.cpp: -------------------------------------------------------------------------------- 1 | #define IMGUI_IMPL_API extern "C" 2 | #include "cimgui/imgui/imgui.h" 3 | //#include "cimgui/imgui/imgui_internal.h" 4 | //#include "cimgui/imgui/imgui_draw.cpp" 5 | #include "cimgui/imgui/imgui.cpp" 6 | //#include "cimgui/imgui/imgui_demo.cpp" 7 | //#include "cimgui/imgui/imgui_widgets.cpp" 8 | 9 | #include "cimgui/cimgui.h" 10 | #include "cimgui/cimgui.cpp" 11 | -------------------------------------------------------------------------------- /code/serialize.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const c = @import("c.zig"); 3 | 4 | fn to_c_string(s: []const u8) []const u8 { 5 | var result = std.heap.direct_allocator.alloc(u8, s.len + 1) catch unreachable; 6 | for (result) |*char, i| { 7 | if (i == s.len) { 8 | char.* = 0; 9 | } else { 10 | char.* = s[i]; 11 | } 12 | } 13 | return result; 14 | } 15 | 16 | pub fn serialize_imgui(variable: var, name: []const u8) void { 17 | const T = @typeOf(variable); 18 | const type_name = @typeName(T); 19 | const c_type_name = to_c_string(type_name); 20 | defer std.heap.direct_allocator.free(c_type_name); 21 | const c_variable_name = to_c_string(name); 22 | defer std.heap.direct_allocator.free(c_variable_name); 23 | switch (@typeInfo(T)) { 24 | .ComptimeInt, .Int => { 25 | c.igText(c"%s:%s = %i", &c_variable_name[0], &c_type_name[0], @intCast(c_int, variable)); 26 | }, 27 | .Float => { 28 | c.igText(c"%s:%s = %f", &c_variable_name[0], &c_type_name[0], variable); 29 | }, 30 | .Void => {}, 31 | .Bool => { 32 | c.igText(c"%s:%s = %s", &c_variable_name[0], &c_type_name[0], if (variable) c"true" else c"false"); 33 | }, 34 | .Optional => { 35 | if (variable) |v| { 36 | // TODO(hugo): member_name ?? 37 | c.igIndent(1.0); 38 | serialize_imgui(v, ""); 39 | c.igUnindent(1.0); 40 | } else { 41 | c.igText(c"%s:%s = null", &c_variable_name[0], &c_type_name[0]); 42 | } 43 | }, 44 | .ErrorUnion => {}, 45 | .ErrorSet => {}, 46 | .Enum => {}, 47 | .Union => {}, 48 | .Struct => { 49 | if (c.igCollapsingHeader(c"Struct", 0)) { 50 | comptime var field_i = 0; 51 | inline while (field_i < @memberCount(T)) : (field_i += 1) { 52 | const member_name = @memberName(T, field_i); 53 | c.igIndent(1.0); 54 | serialize_imgui(@field(variable, member_name), member_name); 55 | c.igUnindent(1.0); 56 | } 57 | } 58 | }, 59 | .Pointer => {}, 60 | .Array => {}, 61 | .Fn => {}, 62 | else => @compileError("Unable to serialize type'" ++ @typeName(T) ++ "'"), 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/sokol/.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | [**] 3 | indent_style=space 4 | indent_size=4 5 | trim_trailing_whitespace=true 6 | insert_final_newline=true 7 | 8 | 9 | -------------------------------------------------------------------------------- /code/sokol/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | #>fips 3 | # this area is managed by fips, do not edit 4 | .fips-* 5 | *.pyc 6 | # 247 | #include 248 | 249 | #ifndef SOKOL_API_DECL 250 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) 251 | #define SOKOL_API_DECL __declspec(dllexport) 252 | #elif defined(_WIN32) && defined(SOKOL_DLL) 253 | #define SOKOL_API_DECL __declspec(dllimport) 254 | #else 255 | #define SOKOL_API_DECL extern 256 | #endif 257 | #endif 258 | 259 | #ifdef __cplusplus 260 | extern "C" { 261 | #endif 262 | 263 | typedef struct sargs_desc { 264 | int argc; 265 | char** argv; 266 | int max_args; 267 | int buf_size; 268 | } sargs_desc; 269 | 270 | /* setup sokol-args */ 271 | SOKOL_API_DECL void sargs_setup(const sargs_desc* desc); 272 | /* shutdown sokol-args */ 273 | SOKOL_API_DECL void sargs_shutdown(void); 274 | /* true between sargs_setup() and sargs_shutdown() */ 275 | SOKOL_API_DECL bool sargs_isvalid(void); 276 | /* test if an argument exists by key name */ 277 | SOKOL_API_DECL bool sargs_exists(const char* key); 278 | /* get value by key name, return empty string if key doesn't exist */ 279 | SOKOL_API_DECL const char* sargs_value(const char* key); 280 | /* get value by key name, return provided default if key doesn't exist */ 281 | SOKOL_API_DECL const char* sargs_value_def(const char* key, const char* def); 282 | /* return true if val arg matches the value associated with key */ 283 | SOKOL_API_DECL bool sargs_equals(const char* key, const char* val); 284 | /* return true if key's value is "true", "yes" or "on" */ 285 | SOKOL_API_DECL bool sargs_boolean(const char* key); 286 | /* get index of arg by key name, return -1 if not exists */ 287 | SOKOL_API_DECL int sargs_find(const char* key); 288 | /* get number of parsed arguments */ 289 | SOKOL_API_DECL int sargs_num_args(void); 290 | /* get key name of argument at index, or empty string */ 291 | SOKOL_API_DECL const char* sargs_key_at(int index); 292 | /* get value string of argument at index, or empty string */ 293 | SOKOL_API_DECL const char* sargs_value_at(int index); 294 | 295 | #ifdef __cplusplus 296 | } /* extern "C" */ 297 | #endif 298 | #endif // SOKOL_ARGS_INCLUDED 299 | 300 | /*--- IMPLEMENTATION ---------------------------------------------------------*/ 301 | #ifdef SOKOL_IMPL 302 | #define SOKOL_ARGS_IMPL_INCLUDED (1) 303 | #include /* memset, strcmp */ 304 | 305 | #if defined(__EMSCRIPTEN__) 306 | #include 307 | #endif 308 | 309 | #ifndef SOKOL_API_IMPL 310 | #define SOKOL_API_IMPL 311 | #endif 312 | #ifndef SOKOL_DEBUG 313 | #ifndef NDEBUG 314 | #define SOKOL_DEBUG (1) 315 | #endif 316 | #endif 317 | #ifndef SOKOL_ASSERT 318 | #include 319 | #define SOKOL_ASSERT(c) assert(c) 320 | #endif 321 | #if !defined(SOKOL_CALLOC) && !defined(SOKOL_FREE) 322 | #include 323 | #endif 324 | #if !defined(SOKOL_CALLOC) 325 | #define SOKOL_CALLOC(n,s) calloc(n,s) 326 | #endif 327 | #if !defined(SOKOL_FREE) 328 | #define SOKOL_FREE(p) free(p) 329 | #endif 330 | #ifndef SOKOL_LOG 331 | #ifdef SOKOL_DEBUG 332 | #include 333 | #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } 334 | #else 335 | #define SOKOL_LOG(s) 336 | #endif 337 | #endif 338 | 339 | #ifndef _SOKOL_PRIVATE 340 | #if defined(__GNUC__) 341 | #define _SOKOL_PRIVATE __attribute__((unused)) static 342 | #else 343 | #define _SOKOL_PRIVATE static 344 | #endif 345 | #endif 346 | 347 | #define _sargs_def(val, def) (((val) == 0) ? (def) : (val)) 348 | 349 | #define _SARGS_MAX_ARGS_DEF (16) 350 | #define _SARGS_BUF_SIZE_DEF (16*1024) 351 | 352 | /* parser state (no parser needed on emscripten) */ 353 | #if !defined(__EMSCRIPTEN__) 354 | #define _SARGS_EXPECT_KEY (1<<0) 355 | #define _SARGS_EXPECT_SEP (1<<1) 356 | #define _SARGS_EXPECT_VAL (1<<2) 357 | #define _SARGS_PARSING_KEY (1<<3) 358 | #define _SARGS_PARSING_VAL (1<<4) 359 | #define _SARGS_ERROR (1<<5) 360 | #endif 361 | 362 | /* a key/value pair struct */ 363 | typedef struct { 364 | int key; /* index to start of key string in buf */ 365 | int val; /* index to start of value string in buf */ 366 | } _sargs_kvp_t; 367 | 368 | /* sokol-args state */ 369 | typedef struct { 370 | int max_args; /* number of key/value pairs in args array */ 371 | int num_args; /* number of valid items in args array */ 372 | _sargs_kvp_t* args; /* key/value pair array */ 373 | int buf_size; /* size of buffer in bytes */ 374 | int buf_pos; /* current buffer position */ 375 | char* buf; /* character buffer, first char is reserved and zero for 'empty string' */ 376 | bool valid; 377 | 378 | /* arg parsing isn't needed on emscripten */ 379 | #if !defined(__EMSCRIPTEN__) 380 | uint32_t parse_state; 381 | char quote; /* current quote char, 0 if not in a quote */ 382 | bool in_escape; /* currently in an escape sequence */ 383 | #endif 384 | } _sargs_state_t; 385 | static _sargs_state_t _sargs; 386 | 387 | /*== PRIVATE IMPLEMENTATION FUNCTIONS ========================================*/ 388 | 389 | _SOKOL_PRIVATE void _sargs_putc(char c) { 390 | if ((_sargs.buf_pos+2) < _sargs.buf_size) { 391 | _sargs.buf[_sargs.buf_pos++] = c; 392 | } 393 | } 394 | 395 | _SOKOL_PRIVATE const char* _sargs_str(int index) { 396 | SOKOL_ASSERT((index >= 0) && (index < _sargs.buf_size)); 397 | return &_sargs.buf[index]; 398 | } 399 | 400 | /*-- argument parser functions (not required on emscripten) ------------------*/ 401 | #if !defined(__EMSCRIPTEN__) 402 | _SOKOL_PRIVATE void _sargs_expect_key(void) { 403 | _sargs.parse_state = _SARGS_EXPECT_KEY; 404 | } 405 | 406 | _SOKOL_PRIVATE bool _sargs_key_expected(void) { 407 | return 0 != (_sargs.parse_state & _SARGS_EXPECT_KEY); 408 | } 409 | 410 | _SOKOL_PRIVATE void _sargs_expect_val(void) { 411 | _sargs.parse_state = _SARGS_EXPECT_VAL; 412 | } 413 | 414 | _SOKOL_PRIVATE bool _sargs_val_expected(void) { 415 | return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL); 416 | } 417 | 418 | _SOKOL_PRIVATE void _sargs_expect_sep(void) { 419 | _sargs.parse_state = _SARGS_EXPECT_SEP; 420 | } 421 | 422 | _SOKOL_PRIVATE bool _sargs_sep_expected(void) { 423 | return 0 != (_sargs.parse_state & _SARGS_EXPECT_SEP); 424 | } 425 | 426 | _SOKOL_PRIVATE bool _sargs_any_expected(void) { 427 | return 0 != (_sargs.parse_state & (_SARGS_EXPECT_KEY | _SARGS_EXPECT_VAL | _SARGS_EXPECT_SEP)); 428 | } 429 | 430 | _SOKOL_PRIVATE bool _sargs_is_separator(char c) { 431 | return c == '='; 432 | } 433 | 434 | _SOKOL_PRIVATE bool _sargs_is_quote(char c) { 435 | if (0 == _sargs.quote) { 436 | return (c == '\'') || (c == '"'); 437 | } 438 | else { 439 | return c == _sargs.quote; 440 | } 441 | } 442 | 443 | _SOKOL_PRIVATE void _sargs_begin_quote(char c) { 444 | _sargs.quote = c; 445 | } 446 | 447 | _SOKOL_PRIVATE void _sargs_end_quote(void) { 448 | _sargs.quote = 0; 449 | } 450 | 451 | _SOKOL_PRIVATE bool _sargs_in_quotes(void) { 452 | return 0 != _sargs.quote; 453 | } 454 | 455 | _SOKOL_PRIVATE bool _sargs_is_whitespace(char c) { 456 | return !_sargs_in_quotes() && ((c == ' ') || (c == '\t')); 457 | } 458 | 459 | _SOKOL_PRIVATE void _sargs_start_key(void) { 460 | SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); 461 | _sargs.parse_state = _SARGS_PARSING_KEY; 462 | _sargs.args[_sargs.num_args].key = _sargs.buf_pos; 463 | } 464 | 465 | _SOKOL_PRIVATE void _sargs_end_key(void) { 466 | SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); 467 | _sargs_putc(0); 468 | _sargs.parse_state = 0; 469 | } 470 | 471 | _SOKOL_PRIVATE bool _sargs_parsing_key(void) { 472 | return 0 != (_sargs.parse_state & _SARGS_PARSING_KEY); 473 | } 474 | 475 | _SOKOL_PRIVATE void _sargs_start_val(void) { 476 | SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); 477 | _sargs.parse_state = _SARGS_PARSING_VAL; 478 | _sargs.args[_sargs.num_args].val = _sargs.buf_pos; 479 | } 480 | 481 | _SOKOL_PRIVATE void _sargs_end_val(void) { 482 | SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); 483 | _sargs_putc(0); 484 | _sargs.num_args++; 485 | _sargs.parse_state = 0; 486 | } 487 | 488 | _SOKOL_PRIVATE bool _sargs_is_escape(char c) { 489 | return '\\' == c; 490 | } 491 | 492 | _SOKOL_PRIVATE void _sargs_start_escape(void) { 493 | _sargs.in_escape = true; 494 | } 495 | 496 | _SOKOL_PRIVATE bool _sargs_in_escape(void) { 497 | return _sargs.in_escape; 498 | } 499 | 500 | _SOKOL_PRIVATE char _sargs_escape(char c) { 501 | switch (c) { 502 | case 'n': return '\n'; 503 | case 't': return '\t'; 504 | case 'r': return '\r'; 505 | case '\\': return '\\'; 506 | default: return c; 507 | } 508 | } 509 | 510 | _SOKOL_PRIVATE void _sargs_end_escape(void) { 511 | _sargs.in_escape = false; 512 | } 513 | 514 | _SOKOL_PRIVATE bool _sargs_parsing_val(void) { 515 | return 0 != (_sargs.parse_state & _SARGS_PARSING_VAL); 516 | } 517 | 518 | _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { 519 | char c; 520 | while (0 != (c = *src++)) { 521 | if (_sargs_in_escape()) { 522 | c = _sargs_escape(c); 523 | _sargs_end_escape(); 524 | } 525 | else if (_sargs_is_escape(c)) { 526 | _sargs_start_escape(); 527 | continue; 528 | } 529 | if (_sargs_any_expected()) { 530 | if (!_sargs_is_whitespace(c)) { 531 | /* start of key, value or separator */ 532 | if (_sargs_key_expected()) { 533 | /* start of new key */ 534 | _sargs_start_key(); 535 | } 536 | else if (_sargs_val_expected()) { 537 | /* start of value */ 538 | if (_sargs_is_quote(c)) { 539 | _sargs_begin_quote(c); 540 | continue; 541 | } 542 | _sargs_start_val(); 543 | } 544 | else { 545 | /* separator */ 546 | if (_sargs_is_separator(c)) { 547 | _sargs_expect_val(); 548 | continue; 549 | } 550 | } 551 | } 552 | else { 553 | /* skip white space */ 554 | continue; 555 | } 556 | } 557 | else if (_sargs_parsing_key()) { 558 | if (_sargs_is_whitespace(c) || _sargs_is_separator(c)) { 559 | /* end of key string */ 560 | _sargs_end_key(); 561 | if (_sargs_is_separator(c)) { 562 | _sargs_expect_val(); 563 | } 564 | else { 565 | _sargs_expect_sep(); 566 | } 567 | continue; 568 | } 569 | } 570 | else if (_sargs_parsing_val()) { 571 | if (_sargs_in_quotes()) { 572 | /* when in quotes, whitespace is a normal character 573 | and a matching quote ends the value string 574 | */ 575 | if (_sargs_is_quote(c)) { 576 | _sargs_end_quote(); 577 | _sargs_end_val(); 578 | _sargs_expect_key(); 579 | continue; 580 | } 581 | } 582 | else if (_sargs_is_whitespace(c)) { 583 | /* end of value string (no quotes) */ 584 | _sargs_end_val(); 585 | _sargs_expect_key(); 586 | continue; 587 | } 588 | } 589 | _sargs_putc(c); 590 | } 591 | if (_sargs_parsing_key()) { 592 | _sargs_end_key(); 593 | _sargs_expect_sep(); 594 | } 595 | else if (_sargs_parsing_val() && !_sargs_in_quotes()) { 596 | _sargs_end_val(); 597 | _sargs_expect_key(); 598 | } 599 | return true; 600 | } 601 | 602 | _SOKOL_PRIVATE bool _sargs_parse_cargs(int argc, const char** argv) { 603 | _sargs_expect_key(); 604 | bool retval = true; 605 | for (int i = 1; i < argc; i++) { 606 | retval &= _sargs_parse_carg(argv[i]); 607 | } 608 | _sargs.parse_state = 0; 609 | return retval; 610 | } 611 | #endif /* __EMSCRIPTEN__ */ 612 | 613 | /*-- EMSCRIPTEN IMPLEMENTATION -----------------------------------------------*/ 614 | #if defined(__EMSCRIPTEN__) 615 | 616 | #ifdef __cplusplus 617 | extern "C" { 618 | #endif 619 | EMSCRIPTEN_KEEPALIVE void _sargs_add_kvp(const char* key, const char* val) { 620 | SOKOL_ASSERT(_sargs.valid && key && val); 621 | if (_sargs.num_args >= _sargs.max_args) { 622 | return; 623 | } 624 | 625 | /* copy key string */ 626 | char c; 627 | _sargs.args[_sargs.num_args].key = _sargs.buf_pos; 628 | const char* ptr = key; 629 | while (0 != (c = *ptr++)) { 630 | _sargs_putc(c); 631 | } 632 | _sargs_putc(0); 633 | 634 | /* copy value string */ 635 | _sargs.args[_sargs.num_args].val = _sargs.buf_pos; 636 | ptr = val; 637 | while (0 != (c = *ptr++)) { 638 | _sargs_putc(c); 639 | } 640 | _sargs_putc(0); 641 | 642 | _sargs.num_args++; 643 | } 644 | #ifdef __cplusplus 645 | } /* extern "C" */ 646 | #endif 647 | 648 | /* JS function to extract arguments from the page URL */ 649 | EM_JS(void, sargs_js_parse_url, (void), { 650 | var params = new URLSearchParams(window.location.search).entries(); 651 | for (var p = params.next(); !p.done; p = params.next()) { 652 | var key = p.value[0]; 653 | var val = p.value[1]; 654 | var res = ccall('_sargs_add_kvp', 'void', ['string','string'], [key,val]); 655 | } 656 | }); 657 | 658 | #endif /* EMSCRIPTEN */ 659 | 660 | /*== PUBLIC IMPLEMENTATION FUNCTIONS =========================================*/ 661 | SOKOL_API_IMPL void sargs_setup(const sargs_desc* desc) { 662 | SOKOL_ASSERT(desc); 663 | memset(&_sargs, 0, sizeof(_sargs)); 664 | _sargs.max_args = _sargs_def(desc->max_args, _SARGS_MAX_ARGS_DEF); 665 | _sargs.buf_size = _sargs_def(desc->buf_size, _SARGS_BUF_SIZE_DEF); 666 | SOKOL_ASSERT(_sargs.buf_size > 8); 667 | _sargs.args = (_sargs_kvp_t*) SOKOL_CALLOC(_sargs.max_args, sizeof(_sargs_kvp_t)); 668 | _sargs.buf = (char*) SOKOL_CALLOC(_sargs.buf_size, sizeof(char)); 669 | /* the first character in buf is reserved and always zero, this is the 'empty string' */ 670 | _sargs.buf_pos = 1; 671 | #if defined(__EMSCRIPTEN__) 672 | /* on emscripten, ignore argc/argv, and parse the page URL instead */ 673 | sargs_js_parse_url(); 674 | #else 675 | /* on native platform, parse argc/argv */ 676 | _sargs_parse_cargs(desc->argc, (const char**) desc->argv); 677 | #endif 678 | _sargs.valid = true; 679 | } 680 | 681 | SOKOL_API_IMPL void sargs_shutdown(void) { 682 | SOKOL_ASSERT(_sargs.valid); 683 | if (_sargs.args) { 684 | SOKOL_FREE(_sargs.args); 685 | _sargs.args = 0; 686 | } 687 | if (_sargs.buf) { 688 | SOKOL_FREE(_sargs.buf); 689 | _sargs.buf = 0; 690 | } 691 | _sargs.valid = false; 692 | } 693 | 694 | SOKOL_API_IMPL bool sargs_isvalid(void) { 695 | return _sargs.valid; 696 | } 697 | 698 | SOKOL_API_IMPL int sargs_find(const char* key) { 699 | SOKOL_ASSERT(_sargs.valid && key); 700 | for (int i = 0; i < _sargs.num_args; i++) { 701 | if (0 == strcmp(_sargs_str(_sargs.args[i].key), key)) { 702 | return i; 703 | } 704 | } 705 | return -1; 706 | } 707 | 708 | SOKOL_API_IMPL int sargs_num_args(void) { 709 | SOKOL_ASSERT(_sargs.valid); 710 | return _sargs.num_args; 711 | } 712 | 713 | SOKOL_API_IMPL const char* sargs_key_at(int index) { 714 | SOKOL_ASSERT(_sargs.valid); 715 | if ((index >= 0) && (index < _sargs.num_args)) { 716 | return _sargs_str(_sargs.args[index].key); 717 | } 718 | else { 719 | /* index 0 is always the empty string */ 720 | return _sargs_str(0); 721 | } 722 | } 723 | 724 | SOKOL_API_IMPL const char* sargs_value_at(int index) { 725 | SOKOL_ASSERT(_sargs.valid); 726 | if ((index >= 0) && (index < _sargs.num_args)) { 727 | return _sargs_str(_sargs.args[index].val); 728 | } 729 | else { 730 | /* index 0 is always the empty string */ 731 | return _sargs_str(0); 732 | } 733 | } 734 | 735 | SOKOL_API_IMPL bool sargs_exists(const char* key) { 736 | SOKOL_ASSERT(_sargs.valid && key); 737 | return -1 != sargs_find(key); 738 | } 739 | 740 | SOKOL_API_IMPL const char* sargs_value(const char* key) { 741 | SOKOL_ASSERT(_sargs.valid && key); 742 | return sargs_value_at(sargs_find(key)); 743 | } 744 | 745 | SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) { 746 | SOKOL_ASSERT(_sargs.valid && key && def); 747 | int arg_index = sargs_find(key); 748 | if (-1 != arg_index) { 749 | return sargs_value_at(arg_index); 750 | } 751 | else { 752 | return def; 753 | } 754 | } 755 | 756 | SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) { 757 | SOKOL_ASSERT(_sargs.valid && key && val); 758 | return 0 == strcmp(sargs_value(key), val); 759 | } 760 | 761 | SOKOL_API_IMPL bool sargs_boolean(const char* key) { 762 | const char* val = sargs_value(key); 763 | return (0 == strcmp("true", val)) || 764 | (0 == strcmp("yes", val)) || 765 | (0 == strcmp("on", val)); 766 | } 767 | 768 | #endif /* SOKOL_IMPL */ 769 | -------------------------------------------------------------------------------- /code/sokol/sokol_time.h: -------------------------------------------------------------------------------- 1 | #ifndef SOKOL_TIME_INCLUDED 2 | /* 3 | sokol_time.h -- simple cross-platform time measurement 4 | 5 | Project URL: https://github.com/floooh/sokol 6 | 7 | Do this: 8 | #define SOKOL_IMPL 9 | before you include this file in *one* C or C++ file to create the 10 | implementation. 11 | 12 | Optionally provide the following defines with your own implementations: 13 | SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) 14 | SOKOL_API_DECL - public function declaration prefix (default: extern) 15 | SOKOL_API_IMPL - public function implementation prefix (default: -) 16 | 17 | If sokol_time.h is compiled as a DLL, define the following before 18 | including the declaration or implementation: 19 | 20 | SOKOL_DLL 21 | 22 | On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport) 23 | or __declspec(dllimport) as needed. 24 | 25 | void stm_setup(); 26 | Call once before any other functions to initialize sokol_time 27 | (this calls for instance QueryPerformanceFrequency on Windows) 28 | 29 | uint64_t stm_now(); 30 | Get current point in time in unspecified 'ticks'. The value that 31 | is returned has no relation to the 'wall-clock' time and is 32 | not in a specific time unit, it is only useful to compute 33 | time differences. 34 | 35 | uint64_t stm_diff(uint64_t new, uint64_t old); 36 | Computes the time difference between new and old. This will always 37 | return a positive, non-zero value. 38 | 39 | uint64_t stm_since(uint64_t start); 40 | Takes the current time, and returns the elapsed time since start 41 | (this is a shortcut for "stm_diff(stm_now(), start)") 42 | 43 | uint64_t stm_laptime(uint64_t* last_time); 44 | This is useful for measuring frame time and other recurring 45 | events. It takes the current time, returns the time difference 46 | to the value in last_time, and stores the current time in 47 | last_time for the next call. If the value in last_time is 0, 48 | the return value will be zero (this usually happens on the 49 | very first call). 50 | 51 | Use the following functions to convert a duration in ticks into 52 | useful time units: 53 | 54 | double stm_sec(uint64_t ticks); 55 | double stm_ms(uint64_t ticks); 56 | double stm_us(uint64_t ticks); 57 | double stm_ns(uint64_t ticks); 58 | Converts a tick value into seconds, milliseconds, microseconds 59 | or nanoseconds. Note that not all platforms will have nanosecond 60 | or even microsecond precision. 61 | 62 | Uses the following time measurement functions under the hood: 63 | 64 | Windows: QueryPerformanceFrequency() / QueryPerformanceCounter() 65 | MacOS/iOS: mach_absolute_time() 66 | emscripten: performance.now() 67 | Linux+others: clock_gettime(CLOCK_MONOTONIC) 68 | 69 | zlib/libpng license 70 | 71 | Copyright (c) 2018 Andre Weissflog 72 | 73 | This software is provided 'as-is', without any express or implied warranty. 74 | In no event will the authors be held liable for any damages arising from the 75 | use of this software. 76 | 77 | Permission is granted to anyone to use this software for any purpose, 78 | including commercial applications, and to alter it and redistribute it 79 | freely, subject to the following restrictions: 80 | 81 | 1. The origin of this software must not be misrepresented; you must not 82 | claim that you wrote the original software. If you use this software in a 83 | product, an acknowledgment in the product documentation would be 84 | appreciated but is not required. 85 | 86 | 2. Altered source versions must be plainly marked as such, and must not 87 | be misrepresented as being the original software. 88 | 89 | 3. This notice may not be removed or altered from any source 90 | distribution. 91 | */ 92 | #define SOKOL_TIME_INCLUDED (1) 93 | #include 94 | 95 | #ifndef SOKOL_API_DECL 96 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) 97 | #define SOKOL_API_DECL __declspec(dllexport) 98 | #elif defined(_WIN32) && defined(SOKOL_DLL) 99 | #define SOKOL_API_DECL __declspec(dllimport) 100 | #else 101 | #define SOKOL_API_DECL extern 102 | #endif 103 | #endif 104 | 105 | #ifdef __cplusplus 106 | extern "C" { 107 | #endif 108 | 109 | SOKOL_API_DECL void stm_setup(void); 110 | SOKOL_API_DECL uint64_t stm_now(void); 111 | SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks); 112 | SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks); 113 | SOKOL_API_DECL uint64_t stm_laptime(uint64_t* last_time); 114 | SOKOL_API_DECL double stm_sec(uint64_t ticks); 115 | SOKOL_API_DECL double stm_ms(uint64_t ticks); 116 | SOKOL_API_DECL double stm_us(uint64_t ticks); 117 | SOKOL_API_DECL double stm_ns(uint64_t ticks); 118 | 119 | #ifdef __cplusplus 120 | } /* extern "C" */ 121 | #endif 122 | #endif // SOKOL_TIME_INCLUDED 123 | 124 | /*-- IMPLEMENTATION ----------------------------------------------------------*/ 125 | #ifdef SOKOL_IMPL 126 | #define SOKOL_TIME_IMPL_INCLUDED (1) 127 | #include /* memset */ 128 | 129 | #ifndef SOKOL_API_IMPL 130 | #define SOKOL_API_IMPL 131 | #endif 132 | #ifndef SOKOL_ASSERT 133 | #include 134 | #define SOKOL_ASSERT(c) assert(c) 135 | #endif 136 | #ifndef _SOKOL_PRIVATE 137 | #if defined(__GNUC__) 138 | #define _SOKOL_PRIVATE __attribute__((unused)) static 139 | #else 140 | #define _SOKOL_PRIVATE static 141 | #endif 142 | #endif 143 | 144 | #if defined(_WIN32) 145 | #ifndef WIN32_LEAN_AND_MEAN 146 | #define WIN32_LEAN_AND_MEAN 147 | #endif 148 | #include 149 | typedef struct { 150 | uint32_t initialized; 151 | LARGE_INTEGER freq; 152 | LARGE_INTEGER start; 153 | } _stm_state_t; 154 | #elif defined(__APPLE__) && defined(__MACH__) 155 | #include 156 | typedef struct { 157 | uint32_t initialized; 158 | mach_timebase_info_data_t timebase; 159 | uint64_t start; 160 | } _stm_state_t; 161 | #elif defined(__EMSCRIPTEN__) 162 | #include 163 | typedef struct { 164 | uint32_t initialized; 165 | double start; 166 | } _stm_state_t; 167 | #else /* anything else, this will need more care for non-Linux platforms */ 168 | #ifdef ESP8266 169 | // On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined 170 | #define CLOCK_MONOTONIC 0 171 | #endif 172 | #include 173 | typedef struct { 174 | uint32_t initialized; 175 | uint64_t start; 176 | } _stm_state_t; 177 | #endif 178 | static _stm_state_t _stm; 179 | 180 | /* prevent 64-bit overflow when computing relative timestamp 181 | see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3 182 | */ 183 | #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) 184 | _SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom) { 185 | int64_t q = value / denom; 186 | int64_t r = value % denom; 187 | return q * numer + r * numer / denom; 188 | } 189 | #endif 190 | 191 | #if defined(__EMSCRIPTEN__) 192 | EM_JS(double, stm_js_perfnow, (void), { 193 | return performance.now(); 194 | }); 195 | #endif 196 | 197 | SOKOL_API_IMPL void stm_setup(void) { 198 | memset(&_stm, 0, sizeof(_stm)); 199 | _stm.initialized = 0xABCDABCD; 200 | #if defined(_WIN32) 201 | QueryPerformanceFrequency(&_stm.freq); 202 | QueryPerformanceCounter(&_stm.start); 203 | #elif defined(__APPLE__) && defined(__MACH__) 204 | mach_timebase_info(&_stm.timebase); 205 | _stm.start = mach_absolute_time(); 206 | #elif defined(__EMSCRIPTEN__) 207 | _stm.start = stm_js_perfnow(); 208 | #else 209 | struct timespec ts; 210 | clock_gettime(CLOCK_MONOTONIC, &ts); 211 | _stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec; 212 | #endif 213 | } 214 | 215 | SOKOL_API_IMPL uint64_t stm_now(void) { 216 | SOKOL_ASSERT(_stm.initialized == 0xABCDABCD); 217 | uint64_t now; 218 | #if defined(_WIN32) 219 | LARGE_INTEGER qpc_t; 220 | QueryPerformanceCounter(&qpc_t); 221 | now = int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart); 222 | #elif defined(__APPLE__) && defined(__MACH__) 223 | const uint64_t mach_now = mach_absolute_time() - _stm.start; 224 | now = int64_muldiv(mach_now, _stm.timebase.numer, _stm.timebase.denom); 225 | #elif defined(__EMSCRIPTEN__) 226 | double js_now = stm_js_perfnow() - _stm.start; 227 | SOKOL_ASSERT(js_now >= 0.0); 228 | now = (uint64_t) (js_now * 1000000.0); 229 | #else 230 | struct timespec ts; 231 | clock_gettime(CLOCK_MONOTONIC, &ts); 232 | now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start; 233 | #endif 234 | return now; 235 | } 236 | 237 | SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) { 238 | if (new_ticks > old_ticks) { 239 | return new_ticks - old_ticks; 240 | } 241 | else { 242 | return 1; 243 | } 244 | } 245 | 246 | SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) { 247 | return stm_diff(stm_now(), start_ticks); 248 | } 249 | 250 | SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) { 251 | SOKOL_ASSERT(last_time); 252 | uint64_t dt = 0; 253 | uint64_t now = stm_now(); 254 | if (0 != *last_time) { 255 | dt = stm_diff(now, *last_time); 256 | } 257 | *last_time = now; 258 | return dt; 259 | } 260 | 261 | SOKOL_API_IMPL double stm_sec(uint64_t ticks) { 262 | return (double)ticks / 1000000000.0; 263 | } 264 | 265 | SOKOL_API_IMPL double stm_ms(uint64_t ticks) { 266 | return (double)ticks / 1000000.0; 267 | } 268 | 269 | SOKOL_API_IMPL double stm_us(uint64_t ticks) { 270 | return (double)ticks / 1000.0; 271 | } 272 | 273 | SOKOL_API_IMPL double stm_ns(uint64_t ticks) { 274 | return (double)ticks; 275 | } 276 | #endif /* SOKOL_IMPL */ 277 | 278 | 279 | -------------------------------------------------------------------------------- /code/sokol/util/README.md: -------------------------------------------------------------------------------- 1 | # Sokol Utility Headers 2 | 3 | These are optional utility headers on top of the Sokol headers. Unlike the 4 | 'core headers' they are not standalone but depend on other Sokol headers 5 | and sometimes also external libraries. 6 | 7 | ### What's in here: 8 | 9 | - **sokol_imgui.h**: implements a renderer for [Dear ImGui](https://github.com/ocornut/imgui) on top of sokol_gfx.h and sokol_app.h (the latter being optional if you do your own input-forwarding to ImGui), the implementation 10 | can be compiled as C++ or C. 11 | - **sokol_gfx_imgui.h**: a debug-inspection UI for sokol_gfx.h, this hooks into the sokol-gfx API and lets you inspect resource objects and captured API calls 12 | - **sokol_gl.h**: an OpenGL 1.x style immediate-mode rendering API 13 | on top of sokol_gfx.h 14 | - **sokol_fontstash.h**: a renderer for [fontstash.h](https://github.com/memononen/fontstash) on 15 | on top of sokol_gl.h 16 | 17 | See the embedded header-documentation for build- and usage-details. 18 | -------------------------------------------------------------------------------- /code/sokol/util/sokol_fontstash.h: -------------------------------------------------------------------------------- 1 | #ifndef SOKOL_FONTSTASH_INCLUDED 2 | /* 3 | sokol_fontstash.h -- renderer for https://github.com/memononen/fontstash 4 | on top of sokol_gl.h 5 | 6 | Project URL: https://github.com/floooh/sokol 7 | 8 | Do this: 9 | 10 | #define SOKOL_FONTSTASH_IMPL 11 | 12 | before you include this file in *one* C or C++ file to create the 13 | implementation. 14 | 15 | The following defines are used by the implementation to select the 16 | platform-specific embedded shader code (these are the same defines as 17 | used by sokol_gfx.h and sokol_app.h): 18 | 19 | SOKOL_GLCORE33 20 | SOKOL_GLES2 21 | SOKOL_GLES3 22 | SOKOL_D3D11 23 | SOKOL_METAL 24 | 25 | ...optionally provide the following macros to override defaults: 26 | 27 | SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) 28 | SOKOL_MALLOC(s) - your own malloc function (default: malloc(s)) 29 | SOKOL_FREE(p) - your own free function (default: free(p)) 30 | SOKOL_API_DECL - public function declaration prefix (default: extern) 31 | SOKOL_API_IMPL - public function implementation prefix (default: -) 32 | SOKOL_LOG(msg) - your own logging function (default: puts(msg)) 33 | SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) 34 | 35 | Include the following headers before including sokol_fontstash.h: 36 | 37 | sokol_gfx.h 38 | 39 | Additionally include the following headers for including the sokol_fontstash.h 40 | implementation: 41 | 42 | sokol_gl.h 43 | 44 | HOW TO 45 | ====== 46 | --- First initialize sokol-gfx and sokol-gl as usual: 47 | 48 | sg_setup(&(sg_desc){...}); 49 | sgl_setup(&(sgl_desc){...}); 50 | 51 | --- Create at least one fontstash context with sfons_create() (this replaces 52 | glfonsCreate() from fontstash.h's example GL renderer: 53 | 54 | FONScontext* ctx = sfons_create(atlas_width, atlas_height, FONS_ZERO_TOPLEFT); 55 | 56 | Each FONScontext manages one font atlas texture which can hold rasterized 57 | glyphs for multiple fonts. 58 | 59 | --- From here on, use fontstash.h's functions "as usual" to add TTF 60 | font data and draw text. Note that (just like with sokol-gl), text 61 | rendering can happen anywhere in the frame, not only inside 62 | a sokol-gfx rendering pass. 63 | 64 | --- You can use the helper function 65 | 66 | uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) 67 | 68 | To convert a 0..255 RGBA color into a packed uint32_t color value 69 | expected by fontstash.h. 70 | 71 | --- Once per frame before calling sgl_draw(), call: 72 | 73 | sfons_flush(FONScontext* ctx) 74 | 75 | ...this will update the dynamic sokol-gfx texture with the latest font 76 | atlas content. 77 | 78 | --- To actually render the text (and any other sokol-gl draw commands), 79 | call sgl_draw() inside a sokol-gfx frame. 80 | 81 | --- NOTE that you can mix fontstash.h calls with sokol-gl calls to mix 82 | text rendering with sokol-gl rendering. You can also use 83 | sokol-gl's matrix stack to position fontstash.h text in 3D. 84 | 85 | --- finally on application shutdown, call: 86 | 87 | sfons_shutdown() 88 | 89 | before sgl_shutdown() and sg_shutdown() 90 | 91 | 92 | WHAT HAPPENS UNDER THE HOOD: 93 | ============================ 94 | 95 | sfons_create(): 96 | - creates a sokol-gfx shader compatible with sokol-gl 97 | - creates an sgl_pipeline object with alpha-blending using 98 | this shader 99 | - creates a 1-byte-per-pixel font atlas texture via sokol-gfx 100 | (pixel format SG_PIXELFORMAT_R8) 101 | 102 | fonsDrawText(): 103 | - this will call the following sequence of sokol-gl functions: 104 | 105 | sgl_enable_texture(); 106 | sgl_texture(...); 107 | sgl_push_pipeline(); 108 | sgl_load_pipeline(...); 109 | sgl_begin_triangles(); 110 | for each vertex: 111 | sg_v2f_t2f_c1i(...); 112 | sgl_end(); 113 | sgl_pop_pipeline(); 114 | sgl_disable_texture(); 115 | 116 | - note that sokol-gl will merge several sgl_*_begin/sgl_end pairs 117 | into a single draw call if no relevant state has changed, typically 118 | all calls to fonsDrawText() will be merged into a single draw call 119 | as long as all calls use the same FONScontext 120 | 121 | sfons_flush(): 122 | - this will call sg_update_image() on the font atlas texture 123 | if fontstash.h has added any rasterized glyphs since the last 124 | frame 125 | 126 | sfons_shutdown(): 127 | - destroy the font atlas texture, sgl_pipeline and sg_shader objects 128 | 129 | LICENSE 130 | ======= 131 | zlib/libpng license 132 | 133 | Copyright (c) 2018 Andre Weissflog 134 | 135 | This software is provided 'as-is', without any express or implied warranty. 136 | In no event will the authors be held liable for any damages arising from the 137 | use of this software. 138 | 139 | Permission is granted to anyone to use this software for any purpose, 140 | including commercial applications, and to alter it and redistribute it 141 | freely, subject to the following restrictions: 142 | 143 | 1. The origin of this software must not be misrepresented; you must not 144 | claim that you wrote the original software. If you use this software in a 145 | product, an acknowledgment in the product documentation would be 146 | appreciated but is not required. 147 | 148 | 2. Altered source versions must be plainly marked as such, and must not 149 | be misrepresented as being the original software. 150 | 151 | 3. This notice may not be removed or altered from any source 152 | distribution. 153 | */ 154 | #define SOKOL_FONTSTASH_INCLUDED (1) 155 | #include 156 | #include 157 | 158 | #if !defined(SOKOL_GFX_INCLUDED) 159 | #error "Please include sokol_gfx.h before sokol_fontstash.h" 160 | #endif 161 | 162 | #ifndef SOKOL_API_DECL 163 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL) 164 | #define SOKOL_API_DECL __declspec(dllexport) 165 | #elif defined(_WIN32) && defined(SOKOL_DLL) 166 | #define SOKOL_API_DECL __declspec(dllimport) 167 | #else 168 | #define SOKOL_API_DECL extern 169 | #endif 170 | #endif 171 | #ifdef __cplusplus 172 | extern "C" { 173 | #endif 174 | 175 | SOKOL_API_DECL FONScontext* sfons_create(int width, int height, int flags); 176 | SOKOL_API_DECL void sfons_destroy(FONScontext* ctx); 177 | SOKOL_API_DECL void sfons_flush(FONScontext* ctx); 178 | SOKOL_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a); 179 | 180 | #ifdef __cplusplus 181 | } /* extern "C" */ 182 | #endif 183 | #endif /* SOKOL_FONTSTASH_INCLUDED */ 184 | 185 | /*-- IMPLEMENTATION ----------------------------------------------------------*/ 186 | #ifdef SOKOL_FONTSTASH_IMPL 187 | #define SOKOL_FONTSTASH_IMPL_INCLUDED (1) 188 | #include /* memset, memcpy */ 189 | 190 | #if !defined(SOKOL_GL_INCLUDED) 191 | #error "Please include sokol_gl.h before sokol_fontstash.h" 192 | #endif 193 | #if !defined(FONS_H) 194 | #error "Please include fontstash.h before sokol_fontstash.h" 195 | #endif 196 | 197 | #ifndef SOKOL_API_IMPL 198 | #define SOKOL_API_IMPL 199 | #endif 200 | #ifndef SOKOL_DEBUG 201 | #ifndef NDEBUG 202 | #define SOKOL_DEBUG (1) 203 | #endif 204 | #endif 205 | #ifndef SOKOL_ASSERT 206 | #include 207 | #define SOKOL_ASSERT(c) assert(c) 208 | #endif 209 | #ifndef SOKOL_MALLOC 210 | #include 211 | #define SOKOL_MALLOC(s) malloc(s) 212 | #define SOKOL_FREE(p) free(p) 213 | #endif 214 | #ifndef SOKOL_LOG 215 | #ifdef SOKOL_DEBUG 216 | #include 217 | #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } 218 | #else 219 | #define SOKOL_LOG(s) 220 | #endif 221 | #endif 222 | #ifndef SOKOL_UNREACHABLE 223 | #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) 224 | #endif 225 | 226 | #if defined(SOKOL_GLCORE33) 227 | static const char* _sfons_vs_src = 228 | "#version 330\n" 229 | "uniform mat4 mvp;\n" 230 | "uniform mat4 tm;\n" 231 | "in vec4 position;\n" 232 | "in vec2 texcoord0;\n" 233 | "in vec4 color0;\n" 234 | "out vec4 uv;\n" 235 | "out vec4 color;\n" 236 | "void main() {\n" 237 | " gl_Position = mvp * position;\n" 238 | " uv = tm * vec4(texcoord0, 0.0, 1.0);\n" 239 | " color = color0;\n" 240 | "}\n"; 241 | static const char* _sfons_fs_src = 242 | "#version 330\n" 243 | "uniform sampler2D tex;\n" 244 | "in vec4 uv;\n" 245 | "in vec4 color;\n" 246 | "out vec4 frag_color;\n" 247 | "void main() {\n" 248 | " frag_color = vec4(1.0, 1.0, 1.0, texture(tex, uv.xy).r) * color;\n" 249 | "}\n"; 250 | #elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3) 251 | static const char* _sfons_vs_src = 252 | "uniform mat4 mvp;\n" 253 | "uniform mat4 tm;\n" 254 | "attribute vec4 position;\n" 255 | "attribute vec2 texcoord0;\n" 256 | "attribute vec4 color0;\n" 257 | "varying vec4 uv;\n" 258 | "varying vec4 color;\n" 259 | "void main() {\n" 260 | " gl_Position = mvp * position;\n" 261 | " uv = tm * vec4(texcoord0, 0.0, 1.0);\n" 262 | " color = color0;\n" 263 | "}\n"; 264 | static const char* _sfons_fs_src = 265 | "precision mediump float;\n" 266 | "uniform sampler2D tex;\n" 267 | "varying vec4 uv;\n" 268 | "varying vec4 color;\n" 269 | "void main() {\n" 270 | " gl_FragColor = vec4(1.0, 1.0, 1.0, texture2D(tex, uv.xy).r) * color;\n" 271 | "}\n"; 272 | #elif defined(SOKOL_METAL) 273 | static const char* _sfons_vs_src = 274 | "#include \n" 275 | "using namespace metal;\n" 276 | "struct params_t {\n" 277 | " float4x4 mvp;\n" 278 | " float4x4 tm;\n" 279 | "};\n" 280 | "struct vs_in {\n" 281 | " float4 pos [[attribute(0)]];\n" 282 | " float2 uv [[attribute(1)]];\n" 283 | " float4 color [[attribute(2)]];\n" 284 | "};\n" 285 | "struct vs_out {\n" 286 | " float4 pos [[position]];\n" 287 | " float4 uv;\n" 288 | " float4 color;\n" 289 | "};\n" 290 | "vertex vs_out _main(vs_in in [[stage_in]], constant params_t& params [[buffer(0)]]) {\n" 291 | " vs_out out;\n" 292 | " out.pos = params.mvp * in.pos;\n" 293 | " out.uv = params.tm * float4(in.uv, 0.0, 1.0);\n" 294 | " out.color = in.color;\n" 295 | " return out;\n" 296 | "}\n"; 297 | static const char* _sfons_fs_src = 298 | "#include \n" 299 | "using namespace metal;\n" 300 | "struct fs_in {\n" 301 | " float4 uv;\n" 302 | " float4 color;\n" 303 | "};\n" 304 | "fragment float4 _main(fs_in in [[stage_in]], texture2d tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n" 305 | " return float4(1.0, 1.0, 1.0, tex.sample(smp, in.uv.xy).r) * in.color;\n" 306 | "}\n"; 307 | #elif defined(SOKOL_D3D11) 308 | /* 309 | Shader blobs for D3D11, compiled with: 310 | 311 | fxc.exe /T vs_4_0 /Fh vs.h /Gec /O3 vs.hlsl 312 | fxc.exe /T ps_4_0 /Fh fs.h /Gec /O3 fs.hlsl 313 | 314 | Vertex shader source: 315 | 316 | cbuffer params: register(b0) { 317 | float4x4 mvp; 318 | float4x4 tm; 319 | }; 320 | struct vs_in { 321 | float4 pos: POSITION; 322 | float2 uv: TEXCOORD0; 323 | float4 color: COLOR0; 324 | }; 325 | struct vs_out { 326 | float4 uv: TEXCOORD0; 327 | float4 color: COLOR0; 328 | float4 pos: SV_Position; 329 | }; 330 | vs_out main(vs_in inp) { 331 | vs_out outp; 332 | outp.pos = mul(mvp, inp.pos); 333 | outp.uv = mul(tm, float4(inp.uv, 0.0, 1.0)); 334 | outp.color = inp.color; 335 | return outp; 336 | }; 337 | 338 | Pixel shader source: 339 | 340 | Texture2D tex: register(t0); 341 | sampler smp: register(s0); 342 | float4 main(float4 uv: TEXCOORD0, float4 color: COLOR0): SV_Target0 { 343 | return float4(1.0, 1.0, 1.0, tex.Sample(smp, uv.xy).r) * color; 344 | } 345 | */ 346 | static const uint8_t _sfons_vs_bin[] = { 347 | 68, 88, 66, 67, 89, 173, 348 | 124, 225, 74, 102, 159, 55, 349 | 47, 64, 241, 32, 31, 107, 350 | 240, 204, 1, 0, 0, 0, 351 | 244, 3, 0, 0, 5, 0, 352 | 0, 0, 52, 0, 0, 0, 353 | 8, 1, 0, 0, 120, 1, 354 | 0, 0, 236, 1, 0, 0, 355 | 120, 3, 0, 0, 82, 68, 356 | 69, 70, 204, 0, 0, 0, 357 | 1, 0, 0, 0, 68, 0, 358 | 0, 0, 1, 0, 0, 0, 359 | 28, 0, 0, 0, 0, 4, 360 | 254, 255, 0, 17, 0, 0, 361 | 163, 0, 0, 0, 60, 0, 362 | 0, 0, 0, 0, 0, 0, 363 | 0, 0, 0, 0, 0, 0, 364 | 0, 0, 0, 0, 0, 0, 365 | 0, 0, 0, 0, 1, 0, 366 | 0, 0, 1, 0, 0, 0, 367 | 112, 97, 114, 97, 109, 115, 368 | 0, 171, 60, 0, 0, 0, 369 | 2, 0, 0, 0, 92, 0, 370 | 0, 0, 128, 0, 0, 0, 371 | 0, 0, 0, 0, 0, 0, 372 | 0, 0, 140, 0, 0, 0, 373 | 0, 0, 0, 0, 64, 0, 374 | 0, 0, 2, 0, 0, 0, 375 | 144, 0, 0, 0, 0, 0, 376 | 0, 0, 160, 0, 0, 0, 377 | 64, 0, 0, 0, 64, 0, 378 | 0, 0, 2, 0, 0, 0, 379 | 144, 0, 0, 0, 0, 0, 380 | 0, 0, 109, 118, 112, 0, 381 | 3, 0, 3, 0, 4, 0, 382 | 4, 0, 0, 0, 0, 0, 383 | 0, 0, 0, 0, 116, 109, 384 | 0, 77, 105, 99, 114, 111, 385 | 115, 111, 102, 116, 32, 40, 386 | 82, 41, 32, 72, 76, 83, 387 | 76, 32, 83, 104, 97, 100, 388 | 101, 114, 32, 67, 111, 109, 389 | 112, 105, 108, 101, 114, 32, 390 | 49, 48, 46, 49, 0, 171, 391 | 73, 83, 71, 78, 104, 0, 392 | 0, 0, 3, 0, 0, 0, 393 | 8, 0, 0, 0, 80, 0, 394 | 0, 0, 0, 0, 0, 0, 395 | 0, 0, 0, 0, 3, 0, 396 | 0, 0, 0, 0, 0, 0, 397 | 15, 15, 0, 0, 89, 0, 398 | 0, 0, 0, 0, 0, 0, 399 | 0, 0, 0, 0, 3, 0, 400 | 0, 0, 1, 0, 0, 0, 401 | 3, 3, 0, 0, 98, 0, 402 | 0, 0, 0, 0, 0, 0, 403 | 0, 0, 0, 0, 3, 0, 404 | 0, 0, 2, 0, 0, 0, 405 | 15, 15, 0, 0, 80, 79, 406 | 83, 73, 84, 73, 79, 78, 407 | 0, 84, 69, 88, 67, 79, 408 | 79, 82, 68, 0, 67, 79, 409 | 76, 79, 82, 0, 79, 83, 410 | 71, 78, 108, 0, 0, 0, 411 | 3, 0, 0, 0, 8, 0, 412 | 0, 0, 80, 0, 0, 0, 413 | 0, 0, 0, 0, 0, 0, 414 | 0, 0, 3, 0, 0, 0, 415 | 0, 0, 0, 0, 15, 0, 416 | 0, 0, 89, 0, 0, 0, 417 | 0, 0, 0, 0, 0, 0, 418 | 0, 0, 3, 0, 0, 0, 419 | 1, 0, 0, 0, 15, 0, 420 | 0, 0, 95, 0, 0, 0, 421 | 0, 0, 0, 0, 1, 0, 422 | 0, 0, 3, 0, 0, 0, 423 | 2, 0, 0, 0, 15, 0, 424 | 0, 0, 84, 69, 88, 67, 425 | 79, 79, 82, 68, 0, 67, 426 | 79, 76, 79, 82, 0, 83, 427 | 86, 95, 80, 111, 115, 105, 428 | 116, 105, 111, 110, 0, 171, 429 | 83, 72, 68, 82, 132, 1, 430 | 0, 0, 64, 0, 1, 0, 431 | 97, 0, 0, 0, 89, 0, 432 | 0, 4, 70, 142, 32, 0, 433 | 0, 0, 0, 0, 8, 0, 434 | 0, 0, 95, 0, 0, 3, 435 | 242, 16, 16, 0, 0, 0, 436 | 0, 0, 95, 0, 0, 3, 437 | 50, 16, 16, 0, 1, 0, 438 | 0, 0, 95, 0, 0, 3, 439 | 242, 16, 16, 0, 2, 0, 440 | 0, 0, 101, 0, 0, 3, 441 | 242, 32, 16, 0, 0, 0, 442 | 0, 0, 101, 0, 0, 3, 443 | 242, 32, 16, 0, 1, 0, 444 | 0, 0, 103, 0, 0, 4, 445 | 242, 32, 16, 0, 2, 0, 446 | 0, 0, 1, 0, 0, 0, 447 | 104, 0, 0, 2, 1, 0, 448 | 0, 0, 56, 0, 0, 8, 449 | 242, 0, 16, 0, 0, 0, 450 | 0, 0, 86, 21, 16, 0, 451 | 1, 0, 0, 0, 70, 142, 452 | 32, 0, 0, 0, 0, 0, 453 | 5, 0, 0, 0, 50, 0, 454 | 0, 10, 242, 0, 16, 0, 455 | 0, 0, 0, 0, 70, 142, 456 | 32, 0, 0, 0, 0, 0, 457 | 4, 0, 0, 0, 6, 16, 458 | 16, 0, 1, 0, 0, 0, 459 | 70, 14, 16, 0, 0, 0, 460 | 0, 0, 0, 0, 0, 8, 461 | 242, 32, 16, 0, 0, 0, 462 | 0, 0, 70, 14, 16, 0, 463 | 0, 0, 0, 0, 70, 142, 464 | 32, 0, 0, 0, 0, 0, 465 | 7, 0, 0, 0, 54, 0, 466 | 0, 5, 242, 32, 16, 0, 467 | 1, 0, 0, 0, 70, 30, 468 | 16, 0, 2, 0, 0, 0, 469 | 56, 0, 0, 8, 242, 0, 470 | 16, 0, 0, 0, 0, 0, 471 | 86, 21, 16, 0, 0, 0, 472 | 0, 0, 70, 142, 32, 0, 473 | 0, 0, 0, 0, 1, 0, 474 | 0, 0, 50, 0, 0, 10, 475 | 242, 0, 16, 0, 0, 0, 476 | 0, 0, 70, 142, 32, 0, 477 | 0, 0, 0, 0, 0, 0, 478 | 0, 0, 6, 16, 16, 0, 479 | 0, 0, 0, 0, 70, 14, 480 | 16, 0, 0, 0, 0, 0, 481 | 50, 0, 0, 10, 242, 0, 482 | 16, 0, 0, 0, 0, 0, 483 | 70, 142, 32, 0, 0, 0, 484 | 0, 0, 2, 0, 0, 0, 485 | 166, 26, 16, 0, 0, 0, 486 | 0, 0, 70, 14, 16, 0, 487 | 0, 0, 0, 0, 50, 0, 488 | 0, 10, 242, 32, 16, 0, 489 | 2, 0, 0, 0, 70, 142, 490 | 32, 0, 0, 0, 0, 0, 491 | 3, 0, 0, 0, 246, 31, 492 | 16, 0, 0, 0, 0, 0, 493 | 70, 14, 16, 0, 0, 0, 494 | 0, 0, 62, 0, 0, 1, 495 | 83, 84, 65, 84, 116, 0, 496 | 0, 0, 9, 0, 0, 0, 497 | 1, 0, 0, 0, 0, 0, 498 | 0, 0, 6, 0, 0, 0, 499 | 7, 0, 0, 0, 0, 0, 500 | 0, 0, 0, 0, 0, 0, 501 | 1, 0, 0, 0, 0, 0, 502 | 0, 0, 0, 0, 0, 0, 503 | 0, 0, 0, 0, 0, 0, 504 | 0, 0, 0, 0, 0, 0, 505 | 0, 0, 0, 0, 0, 0, 506 | 0, 0, 0, 0, 0, 0, 507 | 0, 0, 0, 0, 0, 0, 508 | 0, 0, 0, 0, 0, 0, 509 | 1, 0, 0, 0, 0, 0, 510 | 0, 0, 0, 0, 0, 0, 511 | 0, 0, 0, 0, 0, 0, 512 | 0, 0, 0, 0, 0, 0, 513 | 0, 0, 0, 0, 0, 0, 514 | 0, 0, 0, 0, 0, 0, 515 | 0, 0, 0, 0 516 | }; 517 | static uint8_t _sfons_fs_bin[] = { 518 | 68, 88, 66, 67, 180, 53, 519 | 115, 174, 239, 17, 254, 112, 520 | 63, 104, 217, 123, 150, 145, 521 | 179, 27, 1, 0, 0, 0, 522 | 120, 2, 0, 0, 5, 0, 523 | 0, 0, 52, 0, 0, 0, 524 | 200, 0, 0, 0, 24, 1, 525 | 0, 0, 76, 1, 0, 0, 526 | 252, 1, 0, 0, 82, 68, 527 | 69, 70, 140, 0, 0, 0, 528 | 0, 0, 0, 0, 0, 0, 529 | 0, 0, 2, 0, 0, 0, 530 | 28, 0, 0, 0, 0, 4, 531 | 255, 255, 0, 17, 0, 0, 532 | 100, 0, 0, 0, 92, 0, 533 | 0, 0, 3, 0, 0, 0, 534 | 0, 0, 0, 0, 0, 0, 535 | 0, 0, 0, 0, 0, 0, 536 | 0, 0, 0, 0, 1, 0, 537 | 0, 0, 1, 0, 0, 0, 538 | 96, 0, 0, 0, 2, 0, 539 | 0, 0, 5, 0, 0, 0, 540 | 4, 0, 0, 0, 255, 255, 541 | 255, 255, 0, 0, 0, 0, 542 | 1, 0, 0, 0, 13, 0, 543 | 0, 0, 115, 109, 112, 0, 544 | 116, 101, 120, 0, 77, 105, 545 | 99, 114, 111, 115, 111, 102, 546 | 116, 32, 40, 82, 41, 32, 547 | 72, 76, 83, 76, 32, 83, 548 | 104, 97, 100, 101, 114, 32, 549 | 67, 111, 109, 112, 105, 108, 550 | 101, 114, 32, 49, 48, 46, 551 | 49, 0, 73, 83, 71, 78, 552 | 72, 0, 0, 0, 2, 0, 553 | 0, 0, 8, 0, 0, 0, 554 | 56, 0, 0, 0, 0, 0, 555 | 0, 0, 0, 0, 0, 0, 556 | 3, 0, 0, 0, 0, 0, 557 | 0, 0, 15, 3, 0, 0, 558 | 65, 0, 0, 0, 0, 0, 559 | 0, 0, 0, 0, 0, 0, 560 | 3, 0, 0, 0, 1, 0, 561 | 0, 0, 15, 15, 0, 0, 562 | 84, 69, 88, 67, 79, 79, 563 | 82, 68, 0, 67, 79, 76, 564 | 79, 82, 0, 171, 79, 83, 565 | 71, 78, 44, 0, 0, 0, 566 | 1, 0, 0, 0, 8, 0, 567 | 0, 0, 32, 0, 0, 0, 568 | 0, 0, 0, 0, 0, 0, 569 | 0, 0, 3, 0, 0, 0, 570 | 0, 0, 0, 0, 15, 0, 571 | 0, 0, 83, 86, 95, 84, 572 | 97, 114, 103, 101, 116, 0, 573 | 171, 171, 83, 72, 68, 82, 574 | 168, 0, 0, 0, 64, 0, 575 | 0, 0, 42, 0, 0, 0, 576 | 90, 0, 0, 3, 0, 96, 577 | 16, 0, 0, 0, 0, 0, 578 | 88, 24, 0, 4, 0, 112, 579 | 16, 0, 0, 0, 0, 0, 580 | 85, 85, 0, 0, 98, 16, 581 | 0, 3, 50, 16, 16, 0, 582 | 0, 0, 0, 0, 98, 16, 583 | 0, 3, 242, 16, 16, 0, 584 | 1, 0, 0, 0, 101, 0, 585 | 0, 3, 242, 32, 16, 0, 586 | 0, 0, 0, 0, 104, 0, 587 | 0, 2, 1, 0, 0, 0, 588 | 69, 0, 0, 9, 242, 0, 589 | 16, 0, 0, 0, 0, 0, 590 | 70, 16, 16, 0, 0, 0, 591 | 0, 0, 150, 115, 16, 0, 592 | 0, 0, 0, 0, 0, 96, 593 | 16, 0, 0, 0, 0, 0, 594 | 54, 0, 0, 5, 18, 0, 595 | 16, 0, 0, 0, 0, 0, 596 | 1, 64, 0, 0, 0, 0, 597 | 128, 63, 56, 0, 0, 7, 598 | 242, 32, 16, 0, 0, 0, 599 | 0, 0, 6, 12, 16, 0, 600 | 0, 0, 0, 0, 70, 30, 601 | 16, 0, 1, 0, 0, 0, 602 | 62, 0, 0, 1, 83, 84, 603 | 65, 84, 116, 0, 0, 0, 604 | 4, 0, 0, 0, 1, 0, 605 | 0, 0, 0, 0, 0, 0, 606 | 3, 0, 0, 0, 1, 0, 607 | 0, 0, 0, 0, 0, 0, 608 | 0, 0, 0, 0, 1, 0, 609 | 0, 0, 0, 0, 0, 0, 610 | 0, 0, 0, 0, 0, 0, 611 | 0, 0, 0, 0, 0, 0, 612 | 0, 0, 0, 0, 0, 0, 613 | 0, 0, 1, 0, 0, 0, 614 | 0, 0, 0, 0, 0, 0, 615 | 0, 0, 0, 0, 0, 0, 616 | 0, 0, 0, 0, 1, 0, 617 | 0, 0, 0, 0, 0, 0, 618 | 0, 0, 0, 0, 0, 0, 619 | 0, 0, 0, 0, 0, 0, 620 | 0, 0, 0, 0, 0, 0, 621 | 0, 0, 0, 0, 0, 0, 622 | 0, 0, 0, 0, 0, 0, 623 | 0, 0 624 | }; 625 | #elif defined(SOKOL_DUMMY_BACKEND) 626 | static const char* _sfons_vs_src = ""; 627 | static const char* _sfons_fs_src = ""; 628 | #endif 629 | 630 | typedef struct _sfons_t { 631 | sg_shader shd; 632 | sgl_pipeline pip; 633 | sg_image img; 634 | int width, height; 635 | bool img_dirty; 636 | } _sfons_t; 637 | 638 | static int _sfons_render_create(void* user_ptr, int width, int height) { 639 | SOKOL_ASSERT(user_ptr && (width > 8) && (height > 8)); 640 | _sfons_t* sfons = (_sfons_t*) user_ptr; 641 | 642 | /* sokol-gl compatible shader which treats RED channel as alpha */ 643 | if (sfons->shd.id == SG_INVALID_ID) { 644 | sg_shader_desc shd_desc; 645 | memset(&shd_desc, 0, sizeof(shd_desc)); 646 | shd_desc.attrs[0].name = "position"; 647 | shd_desc.attrs[1].name = "texcoord0"; 648 | shd_desc.attrs[2].name = "color0"; 649 | shd_desc.attrs[0].sem_name = "POSITION"; 650 | shd_desc.attrs[1].sem_name = "TEXCOORD"; 651 | shd_desc.attrs[2].sem_name = "COLOR"; 652 | sg_shader_uniform_block_desc* ub = &shd_desc.vs.uniform_blocks[0]; 653 | ub->size = 128; 654 | ub->uniforms[0].name = "mvp"; 655 | ub->uniforms[0].type = SG_UNIFORMTYPE_MAT4; 656 | ub->uniforms[1].name = "tm"; 657 | ub->uniforms[1].type = SG_UNIFORMTYPE_MAT4; 658 | shd_desc.fs.images[0].name = "tex"; 659 | shd_desc.fs.images[0].type = SG_IMAGETYPE_2D; 660 | #if defined(SOKOL_D3D11) 661 | shd_desc.vs.byte_code = _sfons_vs_bin; 662 | shd_desc.vs.byte_code_size = sizeof(_sfons_vs_bin); 663 | shd_desc.fs.byte_code = _sfons_fs_bin; 664 | shd_desc.fs.byte_code_size = sizeof(_sfons_fs_bin); 665 | #else 666 | shd_desc.vs.source = _sfons_vs_src; 667 | shd_desc.fs.source = _sfons_fs_src; 668 | #endif 669 | shd_desc.label = "sfons-shader"; 670 | sfons->shd = sg_make_shader(&shd_desc); 671 | } 672 | 673 | /* sokol-gl pipeline object */ 674 | if (sfons->pip.id == SG_INVALID_ID) { 675 | sg_pipeline_desc pip_desc; 676 | memset(&pip_desc, 0, sizeof(pip_desc)); 677 | pip_desc.shader = sfons->shd; 678 | pip_desc.blend.enabled = true; 679 | pip_desc.blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; 680 | pip_desc.blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; 681 | sfons->pip = sgl_make_pipeline(&pip_desc); 682 | } 683 | 684 | /* create or re-create font atlas texture */ 685 | if (sfons->img.id != SG_INVALID_ID) { 686 | sg_destroy_image(sfons->img); 687 | sfons->img.id = SG_INVALID_ID; 688 | } 689 | sfons->width = width; 690 | sfons->height = height; 691 | 692 | SOKOL_ASSERT(sfons->img.id == SG_INVALID_ID); 693 | sg_image_desc img_desc; 694 | memset(&img_desc, 0, sizeof(img_desc)); 695 | img_desc.width = sfons->width; 696 | img_desc.height = sfons->height; 697 | img_desc.min_filter = SG_FILTER_LINEAR; 698 | img_desc.mag_filter = SG_FILTER_LINEAR; 699 | img_desc.usage = SG_USAGE_DYNAMIC; 700 | img_desc.pixel_format = SG_PIXELFORMAT_R8; 701 | sfons->img = sg_make_image(&img_desc); 702 | return 1; 703 | } 704 | 705 | static int _sfons_render_resize(void* user_ptr, int width, int height) { 706 | return _sfons_render_create(user_ptr, width, height); 707 | } 708 | 709 | static void _sfons_render_update(void* user_ptr, int* rect, const unsigned char* data) { 710 | SOKOL_ASSERT(user_ptr && rect && data); 711 | _sfons_t* sfons = (_sfons_t*) user_ptr; 712 | sfons->img_dirty = true; 713 | } 714 | 715 | static void _sfons_render_draw(void* user_ptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) { 716 | SOKOL_ASSERT(user_ptr && verts && tcoords && colors && (nverts > 0)); 717 | _sfons_t* sfons = (_sfons_t*) user_ptr; 718 | sgl_enable_texture(); 719 | sgl_texture(sfons->img); 720 | sgl_push_pipeline(); 721 | sgl_load_pipeline(sfons->pip); 722 | sgl_begin_triangles(); 723 | for (int i = 0; i < nverts; i++) { 724 | sgl_v2f_t2f_c1i(verts[2*i+0], verts[2*i+1], tcoords[2*i+0], tcoords[2*i+1], colors[i]); 725 | } 726 | sgl_end(); 727 | sgl_pop_pipeline(); 728 | sgl_disable_texture(); 729 | } 730 | 731 | static void _sfons_render_delete(void* user_ptr) { 732 | SOKOL_ASSERT(user_ptr); 733 | _sfons_t* sfons = (_sfons_t*) user_ptr; 734 | if (sfons->img.id != SG_INVALID_ID) { 735 | sg_destroy_image(sfons->img); 736 | sfons->img.id = SG_INVALID_ID; 737 | } 738 | if (sfons->pip.id != SG_INVALID_ID) { 739 | sgl_destroy_pipeline(sfons->pip); 740 | sfons->pip.id = SG_INVALID_ID; 741 | } 742 | if (sfons->shd.id != SG_INVALID_ID) { 743 | sg_destroy_shader(sfons->shd); 744 | sfons->shd.id = SG_INVALID_ID; 745 | } 746 | SOKOL_FREE(sfons); 747 | } 748 | 749 | SOKOL_API_IMPL FONScontext* sfons_create(int width, int height, int flags) { 750 | SOKOL_ASSERT((width > 0) && (height > 0)); 751 | FONSparams params; 752 | _sfons_t* sfons = (_sfons_t*) SOKOL_MALLOC(sizeof(_sfons_t)); 753 | memset(sfons, 0, sizeof(_sfons_t)); 754 | memset(¶ms, 0, sizeof(params)); 755 | params.width = width; 756 | params.height = height; 757 | params.flags = (unsigned char) flags; 758 | params.renderCreate = _sfons_render_create; 759 | params.renderResize = _sfons_render_resize; 760 | params.renderUpdate = _sfons_render_update; 761 | params.renderDraw = _sfons_render_draw; 762 | params.renderDelete = _sfons_render_delete; 763 | params.userPtr = sfons; 764 | return fonsCreateInternal(¶ms); 765 | } 766 | 767 | SOKOL_API_IMPL void sfons_destroy(FONScontext* ctx) { 768 | SOKOL_ASSERT(ctx); 769 | fonsDeleteInternal(ctx); 770 | } 771 | 772 | SOKOL_API_IMPL void sfons_flush(FONScontext* ctx) { 773 | SOKOL_ASSERT(ctx && ctx->params.userPtr); 774 | _sfons_t* sfons = (_sfons_t*) ctx->params.userPtr; 775 | if (sfons->img_dirty) { 776 | sfons->img_dirty = false; 777 | sg_image_content content; 778 | memset(&content, 0, sizeof(content)); 779 | content.subimage[0][0].ptr = ctx->texData; 780 | content.subimage[0][0].size = sfons->width * sfons->height; 781 | sg_update_image(sfons->img, &content); 782 | } 783 | } 784 | 785 | SOKOL_API_IMPL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { 786 | return (r) | (g<<8) | (b<<16) | (a<<24); 787 | } 788 | 789 | #endif /* SOKOL_FONTSTASH_IMPL */ 790 | -------------------------------------------------------------------------------- /code/sokol_compile.c: -------------------------------------------------------------------------------- 1 | #define SOKOL_IMPL 2 | #define SOKOL_GLCORE33 3 | #include "sokol/sokol_app.h" 4 | #include "sokol/sokol_gfx.h" 5 | #include "sokol/sokol_time.h" 6 | #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS 7 | #include "cimgui/cimgui.h" 8 | #define SOKOL_IMGUI_IMPL 9 | #include "sokol/sokol_imgui.h" 10 | --------------------------------------------------------------------------------