Added ImFontAtlas::GlyphRangesBuilder helper + doc

This commit is contained in:
omar 2017-08-09 22:42:03 +08:00
parent 43e2abbee3
commit 4fd148f4f9
4 changed files with 90 additions and 9 deletions

View File

@ -24,6 +24,7 @@
// Usage, e.g.
ImGui::Text("%s Search", ICON_FA_SEARCH);
---------------------------------
FONTS LOADING INSTRUCTIONS
---------------------------------
@ -84,11 +85,27 @@
font->DisplayOffset.y += 1; // Render 1 pixel down
---------------------------------
BUILDING CUSTOM GLYPH RANGES
---------------------------------
You can use the ImFontAtlas::GlyphRangesBuilder helper to create glyph ranges based on text input.
For exemple: 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.
ImVector<ImWchar> ranges;
ImFontAtlas::GlyphRangesBuilder builder;
builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
builder.AddChar(0x7262); // Add a specific character
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
---------------------------------
REMAPPING CODEPOINTS
---------------------------------
All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work.
All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will NOT work!
In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code.
@ -169,6 +186,9 @@
Inconsolata
http://www.levien.com/type/myfonts/inconsolata.html
Google Noto Fonts (worldwide languages)
https://www.google.com/get/noto/
Adobe Source Code Pro: Monospaced font family for user interface and coding environments
https://github.com/adobe-fonts/source-code-pro

View File

@ -457,15 +457,25 @@
Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will not work.
In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code.
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
io.ImeWindowHandle = MY_HWND; // To input using Microsoft IME, give ImGui the hwnd of your application
// Add default Japanese ranges
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
As for text input, depends on you passing the right character code to io.AddInputCharacter(). The example applications do that.
// Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
ImVector<ImWchar> ranges;
ImFontAtlas::GlyphRangesBuilder builder;
builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
builder.AddChar(0x7262); // Add a specific character
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax.
Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
Text input: it is up to your application to pass the right character code to io.AddInputCharacter(). The applications in examples/ are doing that.
For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle. The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly.
Q: How can I preserve my ImGui context across reloading a DLL? (loss of the global/static variables)
A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()' so you don't rely on the default globals.

15
imgui.h
View File

@ -1350,7 +1350,7 @@ struct ImFontAtlas
void SetTexID(ImTextureID id) { TexID = id; }
// Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
// NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create a UTF-8 string literally using the u8"Hello world" syntax. See FAQ for details.
// NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details.
IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin
IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters
IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
@ -1358,6 +1358,19 @@ struct ImFontAtlas
IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters
// Helpers to build glyph ranges from text data. Feed all your application strings/characters to it then call BuildRanges().
struct GlyphRangesBuilder
{
ImVector<unsigned char> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
GlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); }
bool GetBit(int n) { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; }
void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array
void AddChar(ImWchar c) { SetBit(c); } // Add character
IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault) to force add all of ASCII/Latin+Ext
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
};
// Members
// (Access texture data via GetTexData*() calls which will setup a default font for you.)
ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.

View File

@ -1694,6 +1694,44 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai()
return &ranges[0];
}
//-----------------------------------------------------------------------------
// ImFontAtlas::GlyphRangesBuilder
//-----------------------------------------------------------------------------
void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
{
while (text_end ? (text < text_end) : *text)
{
unsigned int c = 0;
int c_len = ImTextCharFromUtf8(&c, text, text_end);
text += c_len;
if (c_len == 0)
break;
if (c < 0x10000)
AddChar((ImWchar)c);
}
}
void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
{
for (; ranges[0]; ranges += 2)
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
AddChar(c);
}
void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
{
for (int n = 0; n < 0x10000; n++)
if (GetBit(n))
{
out_ranges->push_back((ImWchar)n);
while (n < 0x10000 && GetBit(n + 1))
n++;
out_ranges->push_back((ImWchar)n);
}
out_ranges->push_back(0);
}
//-----------------------------------------------------------------------------
// ImFont
//-----------------------------------------------------------------------------