From f1781c20a300bdb7366d8a4f32a8cb6d891e353d Mon Sep 17 00:00:00 2001 From: septag Date: Fri, 21 Jul 2023 11:38:54 +0200 Subject: [PATCH 01/12] Added IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION config macro to disable stb_sprintf implementation (#6626) --- docs/CHANGELOG.txt | 2 ++ imconfig.h | 3 ++- imgui.cpp | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 34d146b30..5030615d2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other changes: - IO: Changed io.ClearInputsKeys() specs to also clear current frame character buffer (what now obsoleted io.ClearInputCharacters() did), as this is effectively the desirable behavior. +- Misc: Added IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION config macro to disable + stb_sprintf implementation when using IMGUI_USE_STB_SPRINTF. (#6626) [@septag] - Demo: Better showcase use of SetNextItemAllowOverlap(). (#6574, #6512, #3909, #517) - Demo: Showcase a few more InputText() flags. - Backends: Made all backends sources files support global IMGUI_DISABLE. (#6601) diff --git a/imconfig.h b/imconfig.h index bf7fd69a6..886811338 100644 --- a/imconfig.h +++ b/imconfig.h @@ -62,9 +62,10 @@ // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" -//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled +//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. diff --git a/imgui.cpp b/imgui.cpp index 1afaf9e18..a870492fd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1858,13 +1858,15 @@ const char* ImStrSkipBlank(const char* str) // and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) #ifdef IMGUI_USE_STB_SPRINTF +#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION +#endif #ifdef IMGUI_STB_SPRINTF_FILENAME #include IMGUI_STB_SPRINTF_FILENAME #else #include "stb_sprintf.h" #endif -#endif +#endif // #ifdef IMGUI_USE_STB_SPRINTF #if defined(_MSC_VER) && !defined(vsnprintf) #define vsnprintf _vsnprintf From 79d6f4e211f245de24ab7c3a58f33261bd7931bf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Jul 2023 19:45:28 +0200 Subject: [PATCH 02/12] Misc: Avoid stb_textedit.h reincluding string.h while in a namespace. (#6653, #4791) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5030615d2..4bef3a931 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -85,6 +85,8 @@ Other changes: desirable behavior. - Misc: Added IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION config macro to disable stb_sprintf implementation when using IMGUI_USE_STB_SPRINTF. (#6626) [@septag] +- Misc: Avoid stb_textedit.h reincluding string.h while in a namespace, which + messes up with building with Clang Modules. (#6653, #4791) [@JohelEGP] - Demo: Better showcase use of SetNextItemAllowOverlap(). (#6574, #6512, #3909, #517) - Demo: Showcase a few more InputText() flags. - Backends: Made all backends sources files support global IMGUI_DISABLE. (#6601) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d79d1e7c2..1f54616a8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3812,6 +3812,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im #define STB_TEXTEDIT_K_SHIFT 0x400000 #define STB_TEXTEDIT_IMPLEMENTATION +#define STB_TEXTEDIT_memmove memmove #include "imstb_textedit.h" // stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling From 556ce9f543a311455d980912e24131b45f2cf769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Fri, 28 Jul 2023 08:15:10 -0400 Subject: [PATCH 03/12] imgui_stdlib: Fix warning (#6658) --- misc/cpp/imgui_stdlib.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/misc/cpp/imgui_stdlib.cpp b/misc/cpp/imgui_stdlib.cpp index c9060e886..cf69aa89a 100644 --- a/misc/cpp/imgui_stdlib.cpp +++ b/misc/cpp/imgui_stdlib.cpp @@ -10,6 +10,12 @@ #include "imgui.h" #include "imgui_stdlib.h" +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + struct InputTextCallback_UserData { std::string* Str; @@ -73,3 +79,7 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* cb_user_data.ChainCallbackUserData = user_data; return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif From c87b9fdb15e374d7fd5afb3c158a24a3e4bfc8f6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 29 Jul 2023 16:05:13 +0200 Subject: [PATCH 04/12] Docs update. Improved Fonts troubleshooting section. --- docs/FAQ.md | 39 ++------- docs/FONTS.md | 224 +++++++++++++++++++++++++++----------------------- 2 files changed, 125 insertions(+), 138 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 472c1e65c..d0e75799f 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -165,8 +165,8 @@ Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-lik --- ### Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... -Your renderer is not using the font texture correctly or it hasn't been uploaded to the GPU. -- If this happens using the standard backends: A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which could happens if for some reason your texture is too big. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). +Your renderer backend is not using the font texture correctly or it hasn't been uploaded to the GPU. +- If this happens using the standard backends: A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which **can if your texture atlas is too big**. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). - If this happens with a custom backend: make sure you have uploaded the font texture to the GPU, that all shaders are rendering states are setup properly (e.g. texture is bound). Compare your code to existing backends and use a graphics debugger such as [RenderDoc](https://renderdoc.org) to debug your rendering states. ##### [Return to Index](#index) @@ -530,7 +530,7 @@ This approach is relatively easy and functional but comes with two issues: - Style override may be lost during the `Begin()` call crossing monitor boundaries. You may need to do some custom scaling mumbo-jumbo if you want your `OnChangedViewport()` handler to preserve style overrides. Please note that if you are not using multi-viewports with multi-monitors using different DPI scales, you can ignore that and use the simpler technique recommended at the top. - + On Windows, in addition to scaling the font size (make sure to round to an integer) and using `style.ScaleAllSizes()`, you will need to inform Windows that your application is DPI aware. If this is not done, Windows will scale the application window and the UI text will be blurry. Potential solutions to indicate DPI awareness on Windows are: - For SDL: the flag `SDL_WINDOW_ALLOW_HIGHDPI` needs to be passed to `SDL_CreateWindow()``. @@ -570,44 +570,15 @@ io.Fonts->AddFontFromFileTTF("MyFolder/MyFont.ttf", size); // ALSO CORRECT ### Q: How can I easily use icons in my application? The most convenient and practical way is to merge an icon font such as FontAwesome inside your main font. Then you can refer to icons within your strings. -You may want to see `ImFontConfig::GlyphMinAdvanceX` to make your icon look monospace to facilitate alignment. -(Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file for more details about icons font loading.) -With some extra effort, you may use colorful icons by registering custom rectangle space inside the font atlas, -and copying your own graphics data into it. See docs/FONTS.md about using the AddCustomRectFontGlyph API. +Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file for more details about icons font loading. ##### [Return to Index](#index) --- ### Q: How can I load multiple fonts? -Use the font atlas to pack them into a single texture: -(Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file and the code in ImFontAtlas for more details.) -```cpp -ImGuiIO& io = ImGui::GetIO(); -ImFont* font0 = io.Fonts->AddFontDefault(); -ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); -ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); -io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() -// the first loaded font gets used by default -// use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime - -// Options -ImFontConfig config; -config.OversampleH = 2; -config.OversampleV = 1; -config.GlyphOffset.y -= 1.0f; // Move everything by 1 pixel up -config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters -io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, &config); - -// Combine multiple fonts into one (e.g. for icon fonts) -static ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; -ImFontConfig config; -config.MergeMode = true; -io.Fonts->AddFontDefault(); -io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font -io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, nullptr, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs -``` +Use the font atlas to pack them into a single texture. Read [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) for more details. ##### [Return to Index](#index) diff --git a/docs/FONTS.md b/docs/FONTS.md index 6049fb48f..ffd9b80cf 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -11,10 +11,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo **Also read the FAQ:** https://www.dearimgui.com/faq (there is a Fonts section!) ## Index -- [Readme First](#readme-first) -- [About Filenames](#about-filenames) -- [About UTF-8 Encoding](#about-utf-8-encoding) -- [Debug Tools](#debug-tools) +- [Troubleshooting](#troubleshooting) - [How should I handle DPI in my application?](#how-should-i-handle-dpi-in-my-application) - [Fonts Loading Instructions](#fonts-loading-instructions) - [Using Icon Fonts](#using-icon-fonts) @@ -23,103 +20,44 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo - [Using Custom Glyph Ranges](#using-custom-glyph-ranges) - [Using Custom Colorful Icons](#using-custom-colorful-icons) - [Using Font Data Embedded In Source Code](#using-font-data-embedded-in-source-code) +- [About Filenames](#about-filenames) +- [About UTF-8 Encoding](#about-utf-8-encoding) +- [Debug Tools](#debug-tools) - [Credits/Licenses For Fonts Included In Repository](#creditslicenses-for-fonts-included-in-repository) - [Font Links](#font-links) --------------------------------------- -## Readme First +## Troubleshooting -**A vast majority of font and text related issues encountered comes from 3 things:** -- Invalid filename due to use of `\` or unexpected working directory. See [About Filenames](#about-filenames). AddFontXXX functions should assert if the filename is incorrect. -- Invalid UTF-8 encoding of your non-ASCII strings. See [About UTF-8 Encoding](#about-utf-8-encoding). Use the encoding viewer to confirm yours is correct. -- You need to load a font with explicit glyph ranges if you want to use non-ASCII characters. See [Fonts Loading Instructions](#fonts-loading-instructions). Use Metrics/Debugger->Fonts to confirm loaded fonts and loaded glyph ranges. +**A vast majority of font and text related issues encountered comes from 4 things:** -The third point is a current constraint of Dear ImGui (which we will lift in the future): when loading a font you need to specify which characters glyphs to load. -All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas. This is generally called by the Renderer backend, e.g. `ImGui_ImplDX11_NewFrame()` calls it. +### (1) Invalid filename due to use of `\` or unexpected working directory. -**If you use custom glyphs ranges, make sure the array is persistent** and available during the calls to `GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build()`. +See [About Filenames](#about-filenames). AddFontXXX functions should assert if the filename is incorrect. -##### [Return to Index](#index) +### (2) Invalid UTF-8 encoding of your non-ASCII strings. -## About Filenames +See [About UTF-8 Encoding](#about-utf-8-encoding). Use the encoding viewer to confirm encoding of string literal in your source code is correct. -**Please note that many new C/C++ users have issues loading their files _because the filename they provide is wrong_ due to incorrect assumption of what is the current directory.** +### (3) Missing glyph ranges. -Two things to watch for: +You need to load a font with explicit glyph ranges if you want to use non-ASCII characters. See [Fonts Loading Instructions](#fonts-loading-instructions). Use [Debug Tools](#debug-tools) confirm loaded fonts and loaded glyph ranges. -(1) In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. At it happens, Windows uses backslashes as a path separator, so be mindful. -```cpp -io.Fonts->AddFontFromFileTTF("MyFiles\MyImage01.jpg", ...); // This is INCORRECT!! -io.Fonts->AddFontFromFileTTF("MyFiles\\MyImage01.jpg", ...); // This is CORRECT -``` -In some situations, you may also use `/` path separator under Windows. +This is a current constraint of Dear ImGui (which we will lift in the future): when loading a font you need to specify which characters glyphs to load. +All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas. This is generally called by the Renderer backend, e.g. `ImGui_ImplDX11_NewFrame()` calls it. **If you use custom glyphs ranges, make sure the array is persistent** and available during the calls to `GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build()`. -(2) Make sure your IDE/debugger settings starts your executable from the right working (current) directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it often starts from the folder where object or executable files are stored. -```cpp -io.Fonts->AddFontFromFileTTF("MyImage01.jpg", ...); // Relative filename depends on your Working Directory when running your program! -io.Fonts->AddFontFromFileTTF("../MyImage01.jpg", ...); // Load from the parent folder of your Working Directory -``` -##### [Return to Index](#index) +### (4) Font atlas texture fails to upload to GPU. +This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. -## About UTF-8 Encoding - -**For non-ASCII characters display, a common user issue is not passing correctly UTF-8 encoded strings.** - -(1) We provide a function `ImGui::DebugTextEncoding(const char* text)` which you can call to verify the content of your UTF-8 strings. -This is a convenient way to confirm that your encoding is correct. - -```cpp -ImGui::SeparatorText("CORRECT"); -ImGui::DebugTextEncoding(u8"こんにちは"); - -ImGui::SeparatorText("INCORRECT"); -ImGui::DebugTextEncoding("こんにちは"); -``` -![UTF-8 Encoding viewer](https://github.com/ocornut/imgui/assets/8225057/61c1696a-9a94-46c5-9627-cf91211111f0) - -You can also find this tool under `Metrics/Debuggers->Tools->UTF-8 Encoding viewer` if you want to paste from clipboard, but this won't validate the UTF-8 encoding done by your compiler. - -(2) To encode in UTF-8: - -There are also compiler-specific ways to enforce UTF-8 encoding by default: - -- Visual Studio compiler: `/utf-8` command-line flag. -- Visual Studio compiler: `#pragma execution_character_set("utf-8")` inside your code. -- Since May 2023 we have changed the Visual Studio projects of all our examples to use `/utf-8` ([see commit](https://github.com/ocornut/imgui/commit/513af1efc9080857bbd10000d98f98f2a0c96803)). - -Or, since C++11, you can use the `u8"my text"` syntax to encode literal strings as UTF-8. e.g.: -```cpp -ImGui::Text(u8"hello"); -ImGui::Text(u8"こんにちは"); // this will always be encoded as UTF-8 -ImGui::Text("こんにちは"); // the encoding of this is depending on compiler settings/flags and may be incorrect. -``` - -Since C++20, because the C++ committee hate its users, they decided to change the `u8""` syntax to not return `const char*` but a new type `const char_t*` which doesn't cast to `const char*`. -Because of type usage of `u8""` in C++20 is a little more tedious: -```cpp -ImGui::Text((const char*)u8"こんにちは"); -``` -We suggest using a macro in your codebase: -```cpp -#define U8(_S) (const char*)u8##_S -ImGui::Text(U8("こんにちは")); -``` -##### [Return to Index](#index) - - -## Debug Tools - -#### Metrics/Debugger->Fonts -You can use the `Metrics/Debugger` window (available in `Demo>Tools`) to browse your fonts and understand what's going on if you have an issue. You can also reach it in `Demo->Tools->Style Editor->Fonts`. The same information are also available in the Style Editor under Fonts. - -![Fonts debugging](https://user-images.githubusercontent.com/8225057/135429892-0e41ef8d-33c5-4991-bcf6-f997a0bcfd6b.png) - -#### UTF-8 Encoding Viewer** -You can use the `UTF-8 Encoding viewer` in `Metrics/Debugger` to verify the content of your UTF-8 strings. From C/C++ code, you can call `ImGui::DebugTextEncoding("my string");` function to verify that your UTF-8 encoding is correct. - -![UTF-8 Encoding viewer](https://user-images.githubusercontent.com/8225057/166505963-8a0d7899-8ee8-4558-abb2-1ae523dc02f9.png) +Some solutions: +- You may reduce oversampling, e.g. `font_config.OversampleH = 2`, this will largely reduce your texture size. + Note that while OversampleH = 2 looks visibly very close to 3 in most situations, with OversampleH = 1 the quality drop will be noticeable. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). +- Reduce glyphs ranges by calculating them from source localization data. + You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! +- Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. +- Set `io.Fonts.TexDesiredWidth` to specify a texture width to reduce maximum texture height (see comment in `ImFontAtlas::Build()` function). ##### [Return to Index](#index) @@ -144,7 +82,7 @@ io.Fonts->AddFontDefault(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ``` -If you get an assert stating "Could not load font file!", your font filename is likely incorrect. Read "[About filenames](#about-filenames)" carefully. +If you get an assert stating "Could not load font file!", your font filename is likely incorrect. Read [About filenames](#about-filenames) carefully. **Load multiple fonts:** ```cpp @@ -153,8 +91,9 @@ ImGuiIO& io = ImGui::GetIO(); ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); ``` + +In your application loop, select which font to use: ```cpp -// In application loop: select font at runtime ImGui::Text("Hello"); // use the default font (which is the first loaded font) ImGui::PushFont(font2); ImGui::Text("Hello with another font"); @@ -220,22 +159,6 @@ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); ![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_02_jp.png)
_(settings: Dark style (left), Light style (right) / Font: NotoSansCJKjp-Medium, 20px / Rounding: 5)_ -**Font Atlas too large?** - -- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. The typical result of failing to upload a texture is if every glyph appears as a white rectangle. -- Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. - -Some solutions: - -1. Reduce glyphs ranges by calculating them from source localization data. - You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! -2. You may reduce oversampling, e.g. `font_config.OversampleH = 2`, this will largely reduce your texture size. - Note that while OversampleH = 2 looks visibly very close to 3 in most situations, with OversampleH = 1 the quality drop will be noticeable. -3. Set `io.Fonts.TexDesiredWidth` to specify a texture width to minimize texture height (see comment in `ImFontAtlas::Build()` function). -4. Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. -5. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). -6. To support the extended range of unicode beyond 0xFFFF (e.g. emoticons, dingbats, symbols, shapes, ancient languages, etc...) add `#define IMGUI_USE_WCHAR32`in your `imconfig.h`. - ##### [Return to Index](#index) ## Using Icon Fonts @@ -270,6 +193,12 @@ ImGui::Button(ICON_FA_SEARCH " Search"); ``` See Links below for other icons fonts and related tools. +**Monospace Icons?** + +To make your icon look more monospace and facilitate alignment, you may want to set the ImFontConfig::GlyphMinAdvanceX value when loading an icon font. + +**Screenshot** + Here's an application using icons ("Avoyd", https://www.avoyd.com): ![avoyd](https://user-images.githubusercontent.com/8225057/81696852-c15d9e80-9464-11ea-9cab-2a4d4fc84396.jpg) @@ -287,7 +216,7 @@ Here's an application using icons ("Avoyd", https://www.avoyd.com): ## Using Colorful Glyphs/Emojis -- Rendering of colored emojis is only supported by imgui_freetype with FreeType 2.10+. +- Rendering of colored emojis is supported by imgui_freetype with FreeType 2.10+. - You will need to load fonts with the `ImGuiFreeTypeBuilderFlags_LoadColor` flag. - Emojis are frequently encoded in upper Unicode layers (character codes >0x10000) and will need dear imgui compiled with `IMGUI_USE_WCHAR32`. - Not all types of color fonts are supported by FreeType at the moment. @@ -384,6 +313,93 @@ ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_ba ##### [Return to Index](#index) +-- + +## About Filenames + +**Please note that many new C/C++ users have issues loading their files _because the filename they provide is wrong_ due to incorrect assumption of what is the current directory.** + +Two things to watch for: + +(1) In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. At it happens, Windows uses backslashes as a path separator, so be mindful. +```cpp +io.Fonts->AddFontFromFileTTF("MyFiles\MyImage01.jpg", ...); // This is INCORRECT!! +io.Fonts->AddFontFromFileTTF("MyFiles\\MyImage01.jpg", ...); // This is CORRECT +``` +In some situations, you may also use `/` path separator under Windows. + +(2) Make sure your IDE/debugger settings starts your executable from the right working (current) directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it often starts from the folder where object or executable files are stored. +```cpp +io.Fonts->AddFontFromFileTTF("MyImage01.jpg", ...); // Relative filename depends on your Working Directory when running your program! +io.Fonts->AddFontFromFileTTF("../MyImage01.jpg", ...); // Load from the parent folder of your Working Directory +``` +##### [Return to Index](#index) + +-- + +## About UTF-8 Encoding + +**For non-ASCII characters display, a common user issue is not passing correctly UTF-8 encoded strings.** + +(1) We provide a function `ImGui::DebugTextEncoding(const char* text)` which you can call to verify the content of your UTF-8 strings. +This is a convenient way to confirm that your encoding is correct. + +```cpp +ImGui::SeparatorText("CORRECT"); +ImGui::DebugTextEncoding(u8"こんにちは"); + +ImGui::SeparatorText("INCORRECT"); +ImGui::DebugTextEncoding("こんにちは"); +``` +![UTF-8 Encoding viewer](https://github.com/ocornut/imgui/assets/8225057/61c1696a-9a94-46c5-9627-cf91211111f0) + +You can also find this tool under `Metrics/Debuggers->Tools->UTF-8 Encoding viewer` if you want to paste from clipboard, but this won't validate the UTF-8 encoding done by your compiler. + +(2) To encode in UTF-8: + +There are also compiler-specific ways to enforce UTF-8 encoding by default: + +- Visual Studio compiler: `/utf-8` command-line flag. +- Visual Studio compiler: `#pragma execution_character_set("utf-8")` inside your code. +- Since May 2023 we have changed the Visual Studio projects of all our examples to use `/utf-8` ([see commit](https://github.com/ocornut/imgui/commit/513af1efc9080857bbd10000d98f98f2a0c96803)). + +Or, since C++11, you can use the `u8"my text"` syntax to encode literal strings as UTF-8. e.g.: +```cpp +ImGui::Text(u8"hello"); +ImGui::Text(u8"こんにちは"); // this will always be encoded as UTF-8 +ImGui::Text("こんにちは"); // the encoding of this is depending on compiler settings/flags and may be incorrect. +``` + +Since C++20, because the C++ committee hate its users, they decided to change the `u8""` syntax to not return `const char*` but a new type `const char_t*` which doesn't cast to `const char*`. +Because of type usage of `u8""` in C++20 is a little more tedious: +```cpp +ImGui::Text((const char*)u8"こんにちは"); +``` +We suggest using a macro in your codebase: +```cpp +#define U8(_S) (const char*)u8##_S +ImGui::Text(U8("こんにちは")); +``` +##### [Return to Index](#index) + +-- + +## Debug Tools + +#### Metrics/Debugger->Fonts +You can use the `Metrics/Debugger` window (available in `Demo>Tools`) to browse your fonts and understand what's going on if you have an issue. You can also reach it in `Demo->Tools->Style Editor->Fonts`. The same information are also available in the Style Editor under Fonts. + +![Fonts debugging](https://user-images.githubusercontent.com/8225057/135429892-0e41ef8d-33c5-4991-bcf6-f997a0bcfd6b.png) + +#### UTF-8 Encoding Viewer** +You can use the `UTF-8 Encoding viewer` in `Metrics/Debugger` to verify the content of your UTF-8 strings. From C/C++ code, you can call `ImGui::DebugTextEncoding("my string");` function to verify that your UTF-8 encoding is correct. + +![UTF-8 Encoding viewer](https://user-images.githubusercontent.com/8225057/166505963-8a0d7899-8ee8-4558-abb2-1ae523dc02f9.png) + +##### [Return to Index](#index) + +-- + ## Credits/Licenses For Fonts Included In Repository Some fonts files are available in the `misc/fonts/` folder: From eefc9035f070a1430728789b5e8af69e15d89c1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 29 Jul 2023 16:22:30 +0200 Subject: [PATCH 05/12] Fonts: ImFontConfig::OversampleH now defaults to 2 instead of 3. --- docs/CHANGELOG.txt | 2 ++ docs/FONTS.md | 2 +- imgui.h | 2 +- imgui_draw.cpp | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4bef3a931..2ec9b3689 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,8 @@ Breaking changes: Other changes: +- Fonts: ImFontConfig::OversampleH now defaults to 2 instead of 3, since the + quality increase is largely minimal. - ImDrawData: CmdLists[] array is now an ImVector<> owned by ImDrawData rather than a pointer to internal state. - This makes it easier for user to create their own or append to an existing draw data. diff --git a/docs/FONTS.md b/docs/FONTS.md index ffd9b80cf..fa68dad20 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -52,7 +52,7 @@ All loaded fonts glyphs are rendered into a single texture atlas ahead of time. This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. Some solutions: -- You may reduce oversampling, e.g. `font_config.OversampleH = 2`, this will largely reduce your texture size. +- You may reduce oversampling, e.g. `font_config.OversampleH = 1`, this will half your texture size for a quality looss. Note that while OversampleH = 2 looks visibly very close to 3 in most situations, with OversampleH = 1 the quality drop will be noticeable. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). - Reduce glyphs ranges by calculating them from source localization data. You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! diff --git a/imgui.h b/imgui.h index 5610862b0..d126d25e1 100644 --- a/imgui.h +++ b/imgui.h @@ -2773,7 +2773,7 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). int FontNo; // 0 // Index of font within TTF/OTF file float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0f24ca36f..d52e8b95d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1961,7 +1961,7 @@ ImFontConfig::ImFontConfig() { memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - OversampleH = 3; // FIXME: 2 may be a better default? + OversampleH = 2; OversampleV = 1; GlyphMaxAdvanceX = FLT_MAX; RasterizerMultiply = 1.0f; From 7c5b0e829278f10945de7ee4a8b7b567cac1ac69 Mon Sep 17 00:00:00 2001 From: EggsyCRO <39103865+EggsyCRO@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:56:21 +0200 Subject: [PATCH 06/12] Mark alternative ImColor constructors as constexpr (#6656) --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index d126d25e1..14875e536 100644 --- a/imgui.h +++ b/imgui.h @@ -2468,8 +2468,8 @@ struct ImColor constexpr ImColor() { } constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { } constexpr ImColor(const ImVec4& col) : Value(col) {} - ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } - ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } + constexpr ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } + constexpr ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } inline operator ImVec4() const { return Value; } From fa2f1bfbb053b75404dfc13175cd0f59c21bace7 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Mon, 24 Jul 2023 20:17:29 +0200 Subject: [PATCH 07/12] Examples: Vulkan: Fixed Vulkan descriptor pools. (#6642) Only use required no. of types and sets --- docs/CHANGELOG.txt | 1 + examples/example_glfw_vulkan/main.cpp | 16 ++++------------ examples/example_sdl2_vulkan/main.cpp | 16 ++++------------ 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2ec9b3689..331ab2466 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -95,6 +95,7 @@ Other changes: - Backends: GLFW: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609) [@scorpion-26] - Backends: WebGPU: Update for changes in Dawn. (#6602, #6188) [@williamhCode] +- Examples: Vulkan: Creating minimal descriptor pools to fit only what is needed by example. (#6642) [@SaschaWillem] ----------------------------------------------------------------------- diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index c3e7524d5..46af5cc3d 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -215,25 +215,17 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool + // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) + // If you wish to load e.g. additional textures you may need to alter pools sizes. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); + pool_info.maxSets = 1; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 03a952c06..11b274f00 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -203,25 +203,17 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool + // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) + // If you wish to load e.g. additional textures you may need to alter pools sizes. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); + pool_info.maxSets = 1; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); From 88a330ebef31ad2e460c3215215819eb2e459f3a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 29 Jul 2023 17:24:34 +0200 Subject: [PATCH 08/12] Revert "Mark alternative ImColor constructors as constexpr (#6656)" This reverts commit 7c5b0e829278f10945de7ee4a8b7b567cac1ac69. --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 14875e536..d126d25e1 100644 --- a/imgui.h +++ b/imgui.h @@ -2468,8 +2468,8 @@ struct ImColor constexpr ImColor() { } constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { } constexpr ImColor(const ImVec4& col) : Value(col) {} - constexpr ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } - constexpr ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } + ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } + ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } inline operator ImVec4() const { return Value; } From dc2b0a28234efbf62db8bb1453125527e7e94105 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 29 Jul 2023 17:36:50 +0200 Subject: [PATCH 09/12] Disable -Wreserved-identifier warning on Clang (applying to member fields seems excessively weird). --- imgui.h | 9 ++++++--- imgui_draw.cpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index d126d25e1..61773dfe2 100644 --- a/imgui.h +++ b/imgui.h @@ -118,10 +118,13 @@ Index of this file: #endif #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d52e8b95d..d3a332a17 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -63,6 +63,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used From 19ae142bdddf9fcb840549b4b1279739a36c3fa6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 29 Jul 2023 17:48:19 +0200 Subject: [PATCH 10/12] Mark alternative ImColor constructors as constexpr, second attempt (#6656) Earlier 7c5b0e8 broke with VS2015 and some other MingGW/GCC setups. --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 61773dfe2..06f724b8e 100644 --- a/imgui.h +++ b/imgui.h @@ -2471,8 +2471,8 @@ struct ImColor constexpr ImColor() { } constexpr ImColor(float r, float g, float b, float a = 1.0f) : Value(r, g, b, a) { } constexpr ImColor(const ImVec4& col) : Value(col) {} - ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } - ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; } + constexpr ImColor(int r, int g, int b, int a = 255) : Value((float)r * (1.0f / 255.0f), (float)g * (1.0f / 255.0f), (float)b * (1.0f / 255.0f), (float)a* (1.0f / 255.0f)) {} + constexpr ImColor(ImU32 rgba) : Value((float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * (1.0f / 255.0f)) {} inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } inline operator ImVec4() const { return Value; } From 2ad8c60abcd4eb6b6b71003936fde126463ebc5e Mon Sep 17 00:00:00 2001 From: sakiodre <136492105+sakiodre@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:27:08 +0200 Subject: [PATCH 11/12] Fonts: Added support for OpenType SVG fonts using lunasvg (#6591, #6607) --- imconfig.h | 8 ++ misc/freetype/README.md | 8 ++ misc/freetype/imgui_freetype.cpp | 157 +++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) diff --git a/imconfig.h b/imconfig.h index 886811338..fb4d551f1 100644 --- a/imconfig.h +++ b/imconfig.h @@ -80,6 +80,14 @@ // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. //#define IMGUI_ENABLE_STB_TRUETYPE +//---- Use lunasvg library to render OpenType SVG fonts (SVGinOT) +// Requires lunasvg headers to be available in the include path. Requires program to be compiled with the lunasvg library (not provided). +// See https://github.com/ocornut/imgui/tree/master/misc/freetype +// Only works in combination with IMGUI_ENABLE_FREETYPE. +// The implementation is based on the demo https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c +// which is licensed under CeCILL-C Free Software License Agreement +//#define IMGUI_ENABLE_FREETYPE_LUNASVG + //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. // This will be inlined as part of ImVec2 and ImVec4 class declarations. /* diff --git a/misc/freetype/README.md b/misc/freetype/README.md index b25b85d5a..2f4e4db3c 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -35,3 +35,11 @@ You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain color ["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md. ![colored glyphs](https://user-images.githubusercontent.com/8225057/106171241-9dc4ba80-6191-11eb-8a69-ca1467b206d1.png) + + +### Using OpenType SVG fonts (SVGinOT) +- *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. +- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT +- Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above + 1. Add `#define IMGUI_ENABLE_FREETYPE_OTSVG` in your `imconfig.h`. + 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. \ No newline at end of file diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index f1f6b8c5b..2686a54ff 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -6,6 +6,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2023/07/12: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' // 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly. // 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. @@ -44,6 +45,13 @@ #include FT_GLYPH_H // #include FT_SYNTHESIS_H // +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +#include FT_OTSVG_H // +#include FT_BBOX_H // +#include +#include +#endif + #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) @@ -70,6 +78,14 @@ static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFre static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc; static void* GImGuiFreeTypeAllocatorUserData = nullptr; + +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +FT_Error ImGuiLunasvgPortInit(FT_Pointer* state); +void ImGuiLunasvgPortFree(FT_Pointer* state); +FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state); +FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state); +#endif + //------------------------------------------------------------------------- // Code //------------------------------------------------------------------------- @@ -244,7 +260,19 @@ namespace // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; + +#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG + IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); +#else + IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && + "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG" + "in imconfig.h and install required libraries in order to use this font"); IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); +#endif // IMGUI_ENABLE_FREETYPE_LUNASVG +#else + IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); +#endif // ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold) @@ -770,6 +798,18 @@ static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas) // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. FT_Add_Default_Modules(ft_library); +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) + // Install svg hooks for FreeType + // https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks + // https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts + SVG_RendererHooks hooks = {ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot}; + FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks); +#else + IM_ASSERT(!"IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12"); +#endif // ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) +#endif // IMGUI_ENABLE_FREETYPE_LUNASVG + bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags); FT_Done_Library(ft_library); @@ -790,6 +830,123 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u GImGuiFreeTypeAllocatorUserData = user_data; } +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +// For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c +// The original code from the demo is licensed under CeCILL-C Free Software License Agreement +// https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT +typedef struct LunasvgPortState_ +{ + FT_Error err = FT_Err_Ok; + std::unique_ptr svg = nullptr; + lunasvg::Matrix matrix; // Scaled and translated matrix for rendering +} LunasvgPortState, *PLunasvgPortState; + +FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state) +{ + *_state = new LunasvgPortState(); + return FT_Err_Ok; +} + +void ImGuiLunasvgPortFree(FT_Pointer* _state) +{ + delete *_state; +} + +FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state) +{ + PLunasvgPortState state = *(PLunasvgPortState*)_state; + + // If there was an error while loading the svg in + // `ImGuiLunasvgPortPresetSlot`, the renderer hook + // still get called, so just returns the error. + if (state->err != FT_Err_Ok) return state->err; + + // rows is height, pitch (or stride) equals to width * sizeof(int32) + lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch); + + state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value + state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated + + state->err = FT_Err_Ok; + return state->err; +} + +FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state) +{ + FT_SVG_Document document = (FT_SVG_Document)slot->other; + PLunasvgPortState state = *(PLunasvgPortState*)_state; + FT_Size_Metrics& metrics = document->metrics; + + // This function is called twice, once in the `FT_Load_Glyph` + // and another right before `ImGuiLunasvgPortRender`. + // If it's the latter, don't do anything because it's + // already done in the former. + if (cache) return state->err; + + state->svg = lunasvg::Document::loadFromData((const char*)document->svg_document, document->svg_document_length); + if (state->svg == nullptr) + { + state->err = FT_Err_Invalid_SVG_Document; + return state->err; + } + + lunasvg::Box box = state->svg->box(); + + double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h); + double xx = (double)document->transform.xx / (1 << 16); + double xy = -(double)document->transform.xy / (1 << 16); + double yx = -(double)document->transform.yx / (1 << 16); + double yy = (double)document->transform.yy / (1 << 16); + double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem; + double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem; + + // This reset the matrix to its default value + state->matrix.identity(); + + // Scale and transform, we don't translate the svg yet + state->matrix.scale(scale, scale); + state->matrix.transform(xx, xy, yx, yy, x0, y0); + state->svg->setMatrix(state->matrix); + + // Pre-translate the matrix for the rendering step + state->matrix.translate(-box.x, -box.y); + + // Get the box again after the transformation + box = state->svg->box(); + + // Calculate the bitmap size + slot->bitmap_left = FT_Int(box.x); + slot->bitmap_top = FT_Int(-box.y); + slot->bitmap.rows = (unsigned int)(ceil(box.h)); + slot->bitmap.width = (unsigned int)(ceil(box.w)); + slot->bitmap.pitch = slot->bitmap.width * 4; + slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + + // Compute all the bearings and set them correctly. The outline is + // scaled already, we just need to use the bounding box. + double metrics_width = box.w; + double metrics_height = box.h; + double horiBearingX = box.x; + double horiBearingY = -box.y; + + double vertBearingX = slot->metrics.horiBearingX / 64.0 - slot->metrics.horiAdvance / 64.0 / 2.0; + double vertBearingY = (slot->metrics.vertAdvance / 64.0 - slot->metrics.height / 64.0) / 2.0; + + slot->metrics.width = FT_Pos(round(metrics_width * 64.0)); + slot->metrics.height = FT_Pos(round(metrics_height * 64.0)); + + slot->metrics.horiBearingX = FT_Pos(horiBearingX * 64); + slot->metrics.horiBearingY = FT_Pos(horiBearingY * 64); + slot->metrics.vertBearingX = FT_Pos(vertBearingX * 64); + slot->metrics.vertBearingY = FT_Pos(vertBearingY * 64); + + if (slot->metrics.vertAdvance == 0) + slot->metrics.vertAdvance = FT_Pos(metrics_height * 1.2 * 64.0); + + state->err = FT_Err_Ok; + return state->err; +} +#endif // !IMGUI_ENABLE_FREETYPE_LUNASVG //----------------------------------------------------------------------------- #ifdef __GNUC__ From ab490dc7b8da10ed6d6ede4293a28144f50eafa3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 1 Aug 2023 09:33:56 +0200 Subject: [PATCH 12/12] Fonts: Amends for support for OpenType SVG fonts using lunasvg (#6591, #6607) --- docs/CHANGELOG.txt | 3 + imconfig.h | 14 ++--- misc/freetype/README.md | 7 +-- misc/freetype/imgui_freetype.cpp | 104 +++++++++++++------------------ 4 files changed, 55 insertions(+), 73 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 331ab2466..8c7912f6d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,9 @@ Other changes: - Fonts: ImFontConfig::OversampleH now defaults to 2 instead of 3, since the quality increase is largely minimal. +- Fonts, imgui_freetype: Added support to render OpenType SVG fonts using lunasvg. + Requires enabling IMGUI_ENABLE_FREETYPE_LUNASVG along with IMGUI_ENABLE_FREETYPE, + and providing headers/libraries for lunasvg. (#6591, #6607) [@sakiodre] - ImDrawData: CmdLists[] array is now an ImVector<> owned by ImDrawData rather than a pointer to internal state. - This makes it easier for user to create their own or append to an existing draw data. diff --git a/imconfig.h b/imconfig.h index fb4d551f1..b56ba4946 100644 --- a/imconfig.h +++ b/imconfig.h @@ -76,18 +76,16 @@ // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. //#define IMGUI_ENABLE_FREETYPE +//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) +// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). +// Only works in combination with IMGUI_ENABLE_FREETYPE. +// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) +//#define IMGUI_ENABLE_FREETYPE_LUNASVG + //---- Use stb_truetype to build and rasterize the font atlas (default) // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. //#define IMGUI_ENABLE_STB_TRUETYPE -//---- Use lunasvg library to render OpenType SVG fonts (SVGinOT) -// Requires lunasvg headers to be available in the include path. Requires program to be compiled with the lunasvg library (not provided). -// See https://github.com/ocornut/imgui/tree/master/misc/freetype -// Only works in combination with IMGUI_ENABLE_FREETYPE. -// The implementation is based on the demo https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c -// which is licensed under CeCILL-C Free Software License Agreement -//#define IMGUI_ENABLE_FREETYPE_LUNASVG - //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. // This will be inlined as part of ImVec2 and ImVec4 class declarations. /* diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 2f4e4db3c..275a53866 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -22,7 +22,7 @@ See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad ### Known issues -- Oversampling settins are ignored but also not so much necessary with the higher quality rendering. +- Oversampling settings are ignored but also not so much necessary with the higher quality rendering. ### Comparison @@ -36,10 +36,9 @@ You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain color ![colored glyphs](https://user-images.githubusercontent.com/8225057/106171241-9dc4ba80-6191-11eb-8a69-ca1467b206d1.png) - ### Using OpenType SVG fonts (SVGinOT) - *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. - Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT - Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above - 1. Add `#define IMGUI_ENABLE_FREETYPE_OTSVG` in your `imconfig.h`. - 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. \ No newline at end of file + 1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. + 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 2686a54ff..a11e58255 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -6,14 +6,13 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023/07/12: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' +// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' (#6591) // 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly. // 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. // 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a prefered texture format. // 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+). -// 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. -// renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas(). +// 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas(). // 2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. // 2019/02/09: added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!) // 2019/01/15: added support for imgui allocators + added FreeType only override function SetAllocatorFunctions(). @@ -49,7 +48,9 @@ #include FT_OTSVG_H // #include FT_BBOX_H // #include -#include +#if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) +#error IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12 +#endif #endif #ifdef _MSC_VER @@ -78,12 +79,12 @@ static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFre static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc; static void* GImGuiFreeTypeAllocatorUserData = nullptr; - +// Lunasvg support #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG -FT_Error ImGuiLunasvgPortInit(FT_Pointer* state); -void ImGuiLunasvgPortFree(FT_Pointer* state); -FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state); -FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state); +static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state); +static void ImGuiLunasvgPortFree(FT_Pointer* state); +static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state); +static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state); #endif //------------------------------------------------------------------------- @@ -260,19 +261,14 @@ namespace // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; - -#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); #else - IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && - "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG" - "in imconfig.h and install required libraries in order to use this font"); +#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) + IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); +#endif IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG -#else - IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); -#endif // ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold) @@ -799,15 +795,11 @@ static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas) FT_Add_Default_Modules(ft_library); #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG -#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) // Install svg hooks for FreeType // https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks // https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts - SVG_RendererHooks hooks = {ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot}; + SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot }; FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks); -#else - IM_ASSERT(!"IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12"); -#endif // ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) #endif // IMGUI_ENABLE_FREETYPE_LUNASVG bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags); @@ -832,56 +824,51 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG // For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c -// The original code from the demo is licensed under CeCILL-C Free Software License Agreement -// https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT -typedef struct LunasvgPortState_ +// The original code from the demo is licensed under CeCILL-C Free Software License Agreement (https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT) +struct LunasvgPortState { - FT_Error err = FT_Err_Ok; + FT_Error err = FT_Err_Ok; + lunasvg::Matrix matrix; std::unique_ptr svg = nullptr; - lunasvg::Matrix matrix; // Scaled and translated matrix for rendering -} LunasvgPortState, *PLunasvgPortState; +}; -FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state) +static FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state) { - *_state = new LunasvgPortState(); + *_state = IM_NEW(LunasvgPortState)(); return FT_Err_Ok; } -void ImGuiLunasvgPortFree(FT_Pointer* _state) +static void ImGuiLunasvgPortFree(FT_Pointer* _state) { - delete *_state; + IM_DELETE(*_state); } -FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state) +static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state) { - PLunasvgPortState state = *(PLunasvgPortState*)_state; + LunasvgPortState* state = *(LunasvgPortState**)_state; - // If there was an error while loading the svg in - // `ImGuiLunasvgPortPresetSlot`, the renderer hook - // still get called, so just returns the error. - if (state->err != FT_Err_Ok) return state->err; + // If there was an error while loading the svg in ImGuiLunasvgPortPresetSlot(), the renderer hook still get called, so just returns the error. + if (state->err != FT_Err_Ok) + return state->err; // rows is height, pitch (or stride) equals to width * sizeof(int32) lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch); - state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated - state->err = FT_Err_Ok; return state->err; } -FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state) +static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state) { FT_SVG_Document document = (FT_SVG_Document)slot->other; - PLunasvgPortState state = *(PLunasvgPortState*)_state; + LunasvgPortState* state = *(LunasvgPortState**)_state; FT_Size_Metrics& metrics = document->metrics; - // This function is called twice, once in the `FT_Load_Glyph` - // and another right before `ImGuiLunasvgPortRender`. - // If it's the latter, don't do anything because it's - // already done in the former. - if (cache) return state->err; + // This function is called twice, once in the FT_Load_Glyph() and another right before ImGuiLunasvgPortRender(). + // If it's the latter, don't do anything because it's // already done in the former. + if (cache) + return state->err; state->svg = lunasvg::Document::loadFromData((const char*)document->svg_document, document->svg_document_length); if (state->svg == nullptr) @@ -891,7 +878,6 @@ FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer } lunasvg::Box box = state->svg->box(); - double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h); double xx = (double)document->transform.xx / (1 << 16); double xy = -(double)document->transform.xy / (1 << 16); @@ -900,10 +886,8 @@ FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem; double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem; - // This reset the matrix to its default value - state->matrix.identity(); - // Scale and transform, we don't translate the svg yet + state->matrix.identity(); state->matrix.scale(scale, scale); state->matrix.transform(xx, xy, yx, yy, x0, y0); state->svg->setMatrix(state->matrix); @@ -917,24 +901,20 @@ FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer // Calculate the bitmap size slot->bitmap_left = FT_Int(box.x); slot->bitmap_top = FT_Int(-box.y); - slot->bitmap.rows = (unsigned int)(ceil(box.h)); - slot->bitmap.width = (unsigned int)(ceil(box.w)); + slot->bitmap.rows = (unsigned int)(ImCeil((float)box.h)); + slot->bitmap.width = (unsigned int)(ImCeil((float)box.w)); slot->bitmap.pitch = slot->bitmap.width * 4; slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; - // Compute all the bearings and set them correctly. The outline is - // scaled already, we just need to use the bounding box. + // Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box. double metrics_width = box.w; double metrics_height = box.h; double horiBearingX = box.x; double horiBearingY = -box.y; - double vertBearingX = slot->metrics.horiBearingX / 64.0 - slot->metrics.horiAdvance / 64.0 / 2.0; double vertBearingY = (slot->metrics.vertAdvance / 64.0 - slot->metrics.height / 64.0) / 2.0; - - slot->metrics.width = FT_Pos(round(metrics_width * 64.0)); - slot->metrics.height = FT_Pos(round(metrics_height * 64.0)); - + slot->metrics.width = FT_Pos(IM_ROUND(metrics_width * 64.0)); // Using IM_ROUND() assume width and height are positive + slot->metrics.height = FT_Pos(IM_ROUND(metrics_height * 64.0)); slot->metrics.horiBearingX = FT_Pos(horiBearingX * 64); slot->metrics.horiBearingY = FT_Pos(horiBearingY * 64); slot->metrics.vertBearingX = FT_Pos(vertBearingX * 64); @@ -946,7 +926,9 @@ FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer state->err = FT_Err_Ok; return state->err; } -#endif // !IMGUI_ENABLE_FREETYPE_LUNASVG + +#endif // #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG + //----------------------------------------------------------------------------- #ifdef __GNUC__