Merge branch 'master' into navigation

This commit is contained in:
omar 2017-09-26 20:28:40 +02:00
commit 8fd4beddb8
5 changed files with 171 additions and 100 deletions

View File

@ -3751,7 +3751,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex
return ImVec2(0.0f, font_size); return ImVec2(0.0f, font_size);
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
// Cancel out character spacing for the last character of a line (it is baked into glyph->XAdvance field) // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field)
const float font_scale = font_size / font->FontSize; const float font_scale = font_size / font->FontSize;
const float character_spacing_x = 1.0f * font_scale; const float character_spacing_x = 1.0f * font_scale;
if (text_size.x > 0.0f) if (text_size.x > 0.0f)
@ -8750,7 +8750,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Password pushes a temporary font with only a fallback glyph // Password pushes a temporary font with only a fallback glyph
if (is_password) if (is_password)
{ {
const ImFont::Glyph* glyph = g.Font->FindGlyph('*'); const ImFontGlyph* glyph = g.Font->FindGlyph('*');
ImFont* password_font = &g.InputTextPasswordFont; ImFont* password_font = &g.InputTextPasswordFont;
password_font->FontSize = g.Font->FontSize; password_font->FontSize = g.Font->FontSize;
password_font->Scale = g.Font->Scale; password_font->Scale = g.Font->Scale;
@ -8759,8 +8759,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
password_font->Descent = g.Font->Descent; password_font->Descent = g.Font->Descent;
password_font->ContainerAtlas = g.Font->ContainerAtlas; password_font->ContainerAtlas = g.Font->ContainerAtlas;
password_font->FallbackGlyph = glyph; password_font->FallbackGlyph = glyph;
password_font->FallbackXAdvance = glyph->XAdvance; password_font->FallbackAdvanceX = glyph->AdvanceX;
IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexXAdvance.empty() && password_font->IndexLookup.empty()); IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
PushFont(password_font); PushFont(password_font);
} }

108
imgui.h
View File

@ -905,7 +905,7 @@ struct ImGuiIO
ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are negative, so a disappearing/reappearing mouse won't have a huge delta for one frame. ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are negative, so a disappearing/reappearing mouse won't have a huge delta for one frame.
//------------------------------------------------------------------ //------------------------------------------------------------------
// [Private] ImGui will maintain those fields. Forward compatibility not guaranteed! // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed!
//------------------------------------------------------------------ //------------------------------------------------------------------
ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame()) ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame())
@ -1375,7 +1375,7 @@ struct ImFontConfig
float SizePixels; // // Size in pixels for rasterizer. float SizePixels; // // Size in pixels for rasterizer.
int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. 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. 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. ImVec2 GlyphExtraSpacing; // 1, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input.
const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE.
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
@ -1389,6 +1389,14 @@ struct ImFontConfig
IMGUI_API ImFontConfig(); IMGUI_API ImFontConfig();
}; };
struct ImFontGlyph
{
ImWchar Codepoint; // 0x0000..0xFFFF
float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)
float X0, Y0, X1, Y1; // Glyph corners
float U0, V0, U1, V1; // Texture coordinates
};
// Load and rasterize multiple TTF/OTF fonts into a same texture. // Load and rasterize multiple TTF/OTF fonts into a same texture.
// Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering. // Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering.
// We also add custom graphic data into the texture that serves for ImGui. // We also add custom graphic data into the texture that serves for ImGui.
@ -1412,25 +1420,29 @@ struct ImFontAtlas
IMGUI_API void ClearFonts(); // Clear the ImGui-side font data (glyphs storage, UV coordinates) IMGUI_API void ClearFonts(); // Clear the ImGui-side font data (glyphs storage, UV coordinates)
IMGUI_API void Clear(); // Clear all IMGUI_API void Clear(); // Clear all
// Retrieve texture data // Build atlas, retrieve pixel data.
// User is in charge of copying the pixels into graphics memory, then call SetTextureUserID() // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().
// After loading the texture into your graphic system, store your texture handle in 'TexID' (ignore if you aren't using multiple fonts nor images) // RGBA32 format is provided for convenience and compatibility, but note that unless you use CustomRect to draw color data, the RGB pixels emitted from Fonts will all be white (~75% of waste).
// RGBA32 format is provided for convenience and high compatibility, but note that all RGB pixels are white, so 75% of the memory is wasted.
// Pitch = Width * BytesPerPixels // Pitch = Width * BytesPerPixels
IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions.
IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel
void SetTexID(ImTextureID id) { TexID = id; } void SetTexID(ImTextureID id) { TexID = id; }
//-------------------------------------------
// Glyph Ranges
//-------------------------------------------
// Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) // 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 UTF-8 string literal 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* GetGlyphRangesDefault(); // Basic Latin, Extended Latin
IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters
IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Default + Japanese + full set of about 21000 CJK Unified Ideographs
IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai 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(). // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges().
struct GlyphRangesBuilder struct GlyphRangesBuilder
{ {
ImVector<unsigned char> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) ImVector<unsigned char> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
@ -1443,57 +1455,64 @@ struct ImFontAtlas
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
}; };
//-------------------------------------------
// Custom Rectangles/Glyphs API
//-------------------------------------------
// You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels.
// You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs.
struct CustomRect
{
unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
unsigned short Width, Height; // Input // Desired rectangle dimension
unsigned short X, Y; // Output // Packed position in Atlas
float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance
ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset
ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font
CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
bool IsPacked() const { return X != 0xFFFF; }
};
IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font.
IMGUI_API void ClearCustomRects();
IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }
//-------------------------------------------
// Members // 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. 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.
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1.
// [Internal]
// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4
int TexWidth; // Texture width calculated during Build(). int TexWidth; // Texture width calculated during Build().
int TexHeight; // Texture height calculated during Build(). int TexHeight; // Texture height calculated during Build().
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1.
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel
ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
// [Private] User rectangle for packing custom texture data into the atlas.
struct CustomRect
{
unsigned int ID; // Input // User ID. <0x10000 for font mapped data (WIP/UNSUPPORTED), >=0x10000 for other texture data
unsigned short Width, Height; // Input // Desired rectangle dimension
unsigned short X, Y; // Output // Packed position in Atlas
CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; }
bool IsPacked() const { return X != 0xFFFF; }
};
// [Private] Members
ImVector<CustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector<CustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas.
ImVector<ImFontConfig> ConfigData; // Internal data ImVector<ImFontConfig> ConfigData; // Internal data
IMGUI_API bool Build(); // Build pixels data. This is automatically for you by the GetTexData*** functions. int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
IMGUI_API int CustomRectRegister(unsigned int id, int width, int height);
IMGUI_API void CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
}; };
// Font runtime data and rendering // Font runtime data and rendering
// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32().
struct ImFont struct ImFont
{ {
struct Glyph
{
ImWchar Codepoint;
float XAdvance;
float X0, Y0, X1, Y1;
float U0, V0, U1, V1; // Texture coordinates
};
// Members: Hot ~62/78 bytes // Members: Hot ~62/78 bytes
float FontSize; // <user set> // Height of characters, set during loading (don't change after loading) float FontSize; // <user set> // Height of characters, set during loading (don't change after loading)
float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale()
ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels
ImVector<Glyph> Glyphs; // // All glyphs. ImVector<ImFontGlyph> Glyphs; // // All glyphs.
ImVector<float> IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). ImVector<float> IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI).
ImVector<unsigned short> IndexLookup; // // Sparse. Index glyphs by Unicode code-point. ImVector<unsigned short> IndexLookup; // // Sparse. Index glyphs by Unicode code-point.
const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) const ImFontGlyph* FallbackGlyph; // == FindGlyph(FontFallbackChar)
float FallbackXAdvance; // == FallbackGlyph->XAdvance float FallbackAdvanceX; // == FallbackGlyph->AdvanceX
ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar()
// Members: Cold ~18/26 bytes // Members: Cold ~18/26 bytes
@ -1508,9 +1527,9 @@ struct ImFont
IMGUI_API ~ImFont(); IMGUI_API ~ImFont();
IMGUI_API void Clear(); IMGUI_API void Clear();
IMGUI_API void BuildLookupTable(); IMGUI_API void BuildLookupTable();
IMGUI_API const Glyph* FindGlyph(ImWchar c) const; IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const;
IMGUI_API void SetFallbackChar(ImWchar c); IMGUI_API void SetFallbackChar(ImWchar c);
float GetCharAdvance(ImWchar c) const { return ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] : FallbackXAdvance; } float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
bool IsLoaded() const { return ContainerAtlas != NULL; } bool IsLoaded() const { return ContainerAtlas != NULL; }
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
@ -1520,9 +1539,14 @@ struct ImFont
IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const;
IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const;
// Private // [Internal]
IMGUI_API void GrowIndex(int new_size); IMGUI_API void GrowIndex(int new_size);
IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
typedef ImFontGlyph Glyph; // OBSOLETE 1.52+
#endif
}; };
#if defined(__clang__) #if defined(__clang__)

View File

@ -1937,7 +1937,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{ {
// Display all glyphs of the fonts in separate pages of 256 characters // Display all glyphs of the fonts in separate pages of 256 characters
const ImFont::Glyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior. const ImFontGlyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior.
font->FallbackGlyph = NULL; font->FallbackGlyph = NULL;
for (int base = 0; base < 0x10000; base += 256) for (int base = 0; base < 0x10000; base += 256)
{ {
@ -1954,7 +1954,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{ {
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing)); ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing));
ImVec2 cell_p2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y); ImVec2 cell_p2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y);
const ImFont::Glyph* glyph = font->FindGlyph((ImWchar)(base+n));; const ImFontGlyph* glyph = font->FindGlyph((ImWchar)(base+n));;
draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50)); draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50));
font->RenderChar(draw_list, cell_size.x, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. font->RenderChar(draw_list, cell_size.x, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
@ -1962,7 +1962,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text("Codepoint: U+%04X", base+n); ImGui::Text("Codepoint: U+%04X", base+n);
ImGui::Separator(); ImGui::Separator();
ImGui::Text("XAdvance+1: %.1f", glyph->XAdvance); ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
ImGui::EndTooltip(); ImGui::EndTooltip();

View File

@ -1066,7 +1066,7 @@ ImFontConfig::ImFontConfig()
// The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes. // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90; const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90;
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
const int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0xF0000; const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000;
const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
{ {
"..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
@ -1101,11 +1101,14 @@ const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
ImFontAtlas::ImFontAtlas() ImFontAtlas::ImFontAtlas()
{ {
TexID = NULL; TexID = NULL;
TexDesiredWidth = 0;
TexGlyphPadding = 1;
TexPixelsAlpha8 = NULL; TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL; TexPixelsRGBA32 = NULL;
TexWidth = TexHeight = TexDesiredWidth = 0; TexWidth = TexHeight = 0;
TexGlyphPadding = 1;
TexUvWhitePixel = ImVec2(0, 0); TexUvWhitePixel = ImVec2(0, 0);
for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
CustomRectIds[n] = -1;
} }
ImFontAtlas::~ImFontAtlas() ImFontAtlas::~ImFontAtlas()
@ -1122,7 +1125,7 @@ void ImFontAtlas::ClearInputData()
ConfigData[i].FontData = NULL; ConfigData[i].FontData = NULL;
} }
// When clearing this we lose access to the font name and other information used to build the font. // When clearing this we lose access to the font name and other information used to build the font.
for (int i = 0; i < Fonts.Size; i++) for (int i = 0; i < Fonts.Size; i++)
if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
{ {
@ -1318,8 +1321,9 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed
return font; return font;
} }
int ImFontAtlas::CustomRectRegister(unsigned int id, int width, int height) int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
{ {
IM_ASSERT(id >= 0x10000);
IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF);
CustomRect r; CustomRect r;
@ -1330,7 +1334,23 @@ int ImFontAtlas::CustomRectRegister(unsigned int id, int width, int height)
return CustomRects.Size - 1; // Return index return CustomRects.Size - 1; // Return index
} }
void ImFontAtlas::CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
{
IM_ASSERT(font != NULL);
IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF);
CustomRect r;
r.ID = id;
r.Width = (unsigned short)width;
r.Height = (unsigned short)height;
r.GlyphAdvanceX = advance_x;
r.GlyphOffset = offset;
r.Font = font;
CustomRects.push_back(r);
return CustomRects.Size - 1; // Return index
}
void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
{ {
IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
@ -1535,26 +1555,9 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
stbtt_aligned_quad q; stbtt_aligned_quad q;
float dummy_x = 0.0f, dummy_y = 0.0f; float dummy_x = 0.0f, dummy_y = 0.0f;
stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0); stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
dst_font->Glyphs.resize(dst_font->Glyphs.Size + 1);
ImFont::Glyph& glyph = dst_font->Glyphs.back();
glyph.Codepoint = (ImWchar)codepoint;
glyph.X0 = q.x0 + off_x;
glyph.Y0 = q.y0 + off_y;
glyph.X1 = q.x1 + off_x;
glyph.Y1 = q.y1 + off_y;
glyph.U0 = q.s0;
glyph.V0 = q.t0;
glyph.U1 = q.s1;
glyph.V1 = q.t1;
glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance
if (cfg.PixelSnapH)
glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f);
dst_font->MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * atlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * atlas->TexHeight + 1.99f); // +1 to account for average padding, +0.99 to round
} }
} }
cfg.DstFont->BuildLookupTable();
} }
// Cleanup temporaries // Cleanup temporaries
@ -1562,17 +1565,15 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
ImGui::MemFree(buf_ranges); ImGui::MemFree(buf_ranges);
ImGui::MemFree(tmp_array); ImGui::MemFree(tmp_array);
// Render into our custom data block ImFontAtlasBuildFinish(atlas);
ImFontAtlasBuildRenderDefaultTexData(atlas);
return true; return true;
} }
void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas) void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas)
{ {
// FIXME-WIP: We should register in the constructor (but cannot because our static instances may not have allocator ready by the time they initialize). This needs to be fixed because we can expose CustomRects. if (atlas->CustomRectIds[0] < 0)
if (atlas->CustomRects.empty()) atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
atlas->CustomRectRegister(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
} }
void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
@ -1615,9 +1616,10 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaq
} }
} }
void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
{ {
ImFontAtlas::CustomRect& r = atlas->CustomRects[0]; IM_ASSERT(atlas->CustomRectIds[0] >= 0);
ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1); IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1);
IM_ASSERT(r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); IM_ASSERT(r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
@ -1665,6 +1667,29 @@ void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
} }
} }
void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
{
// Render into our custom data block
ImFontAtlasBuildRenderDefaultTexData(atlas);
// Register custom rectangle glyphs
for (int i = 0; i < atlas->CustomRects.Size; i++)
{
const ImFontAtlas::CustomRect& r = atlas->CustomRects[i];
if (r.Font == NULL || r.ID > 0x10000)
continue;
IM_ASSERT(r.Font->ContainerAtlas == atlas);
ImVec2 uv0, uv1;
atlas->CalcCustomRectUV(&r, &uv0, &uv1);
r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX);
}
// Build all fonts lookup tables
for (int i = 0; i < atlas->Fonts.Size; i++)
atlas->Fonts[i]->BuildLookupTable();
}
// Retrieve list of range (2 int per range, values are inclusive) // Retrieve list of range (2 int per range, values are inclusive)
const ImWchar* ImFontAtlas::GetGlyphRangesDefault() const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
{ {
@ -1858,10 +1883,10 @@ void ImFont::Clear()
FontSize = 0.0f; FontSize = 0.0f;
DisplayOffset = ImVec2(0.0f, 1.0f); DisplayOffset = ImVec2(0.0f, 1.0f);
Glyphs.clear(); Glyphs.clear();
IndexXAdvance.clear(); IndexAdvanceX.clear();
IndexLookup.clear(); IndexLookup.clear();
FallbackGlyph = NULL; FallbackGlyph = NULL;
FallbackXAdvance = 0.0f; FallbackAdvanceX = 0.0f;
ConfigDataCount = 0; ConfigDataCount = 0;
ConfigData = NULL; ConfigData = NULL;
ContainerAtlas = NULL; ContainerAtlas = NULL;
@ -1876,13 +1901,13 @@ void ImFont::BuildLookupTable()
max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
IndexXAdvance.clear(); IndexAdvanceX.clear();
IndexLookup.clear(); IndexLookup.clear();
GrowIndex(max_codepoint + 1); GrowIndex(max_codepoint + 1);
for (int i = 0; i < Glyphs.Size; i++) for (int i = 0; i < Glyphs.Size; i++)
{ {
int codepoint = (int)Glyphs[i].Codepoint; int codepoint = (int)Glyphs[i].Codepoint;
IndexXAdvance[codepoint] = Glyphs[i].XAdvance; IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
IndexLookup[codepoint] = (unsigned short)i; IndexLookup[codepoint] = (unsigned short)i;
} }
@ -1892,20 +1917,20 @@ void ImFont::BuildLookupTable()
{ {
if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
Glyphs.resize(Glyphs.Size + 1); Glyphs.resize(Glyphs.Size + 1);
ImFont::Glyph& tab_glyph = Glyphs.back(); ImFontGlyph& tab_glyph = Glyphs.back();
tab_glyph = *FindGlyph((unsigned short)' '); tab_glyph = *FindGlyph((unsigned short)' ');
tab_glyph.Codepoint = '\t'; tab_glyph.Codepoint = '\t';
tab_glyph.XAdvance *= 4; tab_glyph.AdvanceX *= 4;
IndexXAdvance[(int)tab_glyph.Codepoint] = (float)tab_glyph.XAdvance; IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1); IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1);
} }
FallbackGlyph = NULL; FallbackGlyph = NULL;
FallbackGlyph = FindGlyph(FallbackChar); FallbackGlyph = FindGlyph(FallbackChar);
FallbackXAdvance = FallbackGlyph ? FallbackGlyph->XAdvance : 0.0f; FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
for (int i = 0; i < max_codepoint + 1; i++) for (int i = 0; i < max_codepoint + 1; i++)
if (IndexXAdvance[i] < 0.0f) if (IndexAdvanceX[i] < 0.0f)
IndexXAdvance[i] = FallbackXAdvance; IndexAdvanceX[i] = FallbackAdvanceX;
} }
void ImFont::SetFallbackChar(ImWchar c) void ImFont::SetFallbackChar(ImWchar c)
@ -1916,13 +1941,35 @@ void ImFont::SetFallbackChar(ImWchar c)
void ImFont::GrowIndex(int new_size) void ImFont::GrowIndex(int new_size)
{ {
IM_ASSERT(IndexXAdvance.Size == IndexLookup.Size); IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
if (new_size <= IndexLookup.Size) if (new_size <= IndexLookup.Size)
return; return;
IndexXAdvance.resize(new_size, -1.0f); IndexAdvanceX.resize(new_size, -1.0f);
IndexLookup.resize(new_size, (unsigned short)-1); IndexLookup.resize(new_size, (unsigned short)-1);
} }
void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
{
Glyphs.resize(Glyphs.Size + 1);
ImFontGlyph& glyph = Glyphs.back();
glyph.Codepoint = (ImWchar)codepoint;
glyph.X0 = x0;
glyph.Y0 = y0;
glyph.X1 = x1;
glyph.Y1 = y1;
glyph.U0 = u0;
glyph.V0 = v0;
glyph.U1 = u1;
glyph.V1 = v1;
glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX
if (ConfigData->PixelSnapH)
glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);
// Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f);
}
void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
{ {
IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
@ -1935,10 +1982,10 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
GrowIndex(dst + 1); GrowIndex(dst + 1);
IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1; IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f; IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
} }
const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const const ImFontGlyph* ImFont::FindGlyph(unsigned short c) const
{ {
if (c < IndexLookup.Size) if (c < IndexLookup.Size)
{ {
@ -2003,7 +2050,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
} }
} }
const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance); const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
if (ImCharIsSpace(c)) if (ImCharIsSpace(c))
{ {
if (inside_word) if (inside_word)
@ -2120,7 +2167,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
continue; continue;
} }
const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance) * scale; const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
if (line_width + char_width >= max_width) if (line_width + char_width >= max_width)
{ {
s = prev_s; s = prev_s;
@ -2146,7 +2193,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
{ {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
return; return;
if (const Glyph* glyph = FindGlyph(c)) if (const ImFontGlyph* glyph = FindGlyph(c))
{ {
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
pos.x = (float)(int)pos.x + DisplayOffset.x; pos.x = (float)(int)pos.x + DisplayOffset.x;
@ -2250,9 +2297,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
} }
float char_width = 0.0f; float char_width = 0.0f;
if (const Glyph* glyph = FindGlyph((unsigned short)c)) if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c))
{ {
char_width = glyph->XAdvance * scale; char_width = glyph->AdvanceX * scale;
// Arbitrarily assume that both space and tabs are empty glyphs as an optimization // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
if (c != ' ' && c != '\t') if (c != ' ' && c != '\t')

View File

@ -921,7 +921,7 @@ IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc); IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc);
IMGUI_API void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);