ImFontAtlas allows loading multiple fonts into same texture. Revamped new init API for 1.30

This commit is contained in:
ocornut 2015-01-17 22:15:29 +00:00
parent cb9a3235be
commit 2c31599bcc
6 changed files with 488 additions and 335 deletions

View File

@ -321,7 +321,7 @@ void CleanupDevice()
// InitImGui
if (g_pFontSampler) g_pFontSampler->Release();
if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().Font->TexID)
if (ID3D11ShaderResourceView* font_texture_view = (ID3D11ShaderResourceView*)ImGui::GetIO().FontAtlas->TexID)
font_texture_view->Release();
if (g_pVB) g_pVB->Release();
@ -377,11 +377,17 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void LoadFontTexture(ImFont* font)
void LoadFontTexture()
{
// Load one or more font
ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font = io.FontAtlas->AddFontDefault();
//ImFont* my_font2 = io.FontAtlas->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 20.0f, ImFontAtlas::GetGlyphRangesJapanese());
// Build
unsigned char* pixels;
int width, height;
font->GetTextureDataRGBA32(&pixels, &width, &height);
io.FontAtlas->GetTexDataAsRGBA32(&pixels, &width, &height);
// Create texture
D3D11_TEXTURE2D_DESC desc;
@ -414,8 +420,8 @@ void LoadFontTexture(ImFont* font)
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &font_texture_view);
pTexture->Release();
// Store ID
font->TexID = (void *)font_texture_view;
// Store our identifier
io.FontAtlas->TexID = (void *)font_texture_view;
}
void InitImGui()
@ -463,10 +469,8 @@ void InitImGui()
}
}
// Load font (optionally load a custom TTF font)
//io.Font->LoadFromFileTTF("myfont.ttf", font_size_px, ImFont::GetGlyphRangesDefault());
//io.Font->DisplayOffset.y += 1.0f;
LoadFontTexture(io.Font);
// Load fonts
LoadFontTexture();
// Create texture sampler
{

View File

@ -73,8 +73,8 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
// Setup orthographic projection matrix
D3DXMATRIXA16 mat;
@ -129,7 +129,7 @@ void CleanupDevice()
if (g_pVB) g_pVB->Release();
// InitDeviceD3D
if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().Font->TexID)
if (LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)ImGui::GetIO().FontAtlas->TexID)
tex->Release();
if (g_pd3dDevice) g_pd3dDevice->Release();
if (g_pD3D) g_pD3D->Release();
@ -173,13 +173,19 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
return DefWindowProc(hWnd, msg, wParam, lParam);
}
void LoadFontTexture(ImFont* font)
void LoadFontTexture()
{
unsigned char* pixels;
int width, height;
int bytes_per_pixel;
font->GetTextureDataAlpha8(&pixels, &width, &height, &bytes_per_pixel);
// Load one or more font
ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font = io.FontAtlas->AddFontDefault();
//ImFont* my_font2 = io.FontAtlas->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 20.0f, ImFontAtlas::GetGlyphRangesJapanese());
// Build
unsigned char* pixels;
int width, height, bytes_per_pixel;
io.FontAtlas->GetTexDataAsAlpha8(&pixels, &width, &height, &bytes_per_pixel);
// Create texture
LPDIRECT3DTEXTURE9 pTexture = NULL;
if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &pTexture) < 0)
{
@ -198,7 +204,8 @@ void LoadFontTexture(ImFont* font)
memcpy((unsigned char *)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
pTexture->UnlockRect(0);
font->TexID = (void *)pTexture;
// Store our identifier
io.FontAtlas->TexID = (void *)pTexture;
}
void InitImGui()
@ -238,10 +245,7 @@ void InitImGui()
return;
}
// Load font (optionally load a custom TTF font)
//io.Font->LoadFromFileTTF("myfont.ttf", font_size_px, ImFont::GetGlyphRangesDefault());
//io.Font->DisplayOffset.y += 1.0f;
LoadFontTexture(io.Font);
LoadFontTexture();
}
INT64 ticks_per_second = 0;

View File

@ -235,20 +235,25 @@ void InitGL()
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void LoadFontTexture(ImFont* font)
void LoadFontTexture()
{
ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font = io.FontAtlas->AddFontDefault();
//ImFont* my_font2 = io.FontAtlas->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 20.0f, ImFontAtlas::GetGlyphRangesJapanese());
unsigned char* pixels;
int width, height;
font->GetTextureDataRGBA32(&pixels, &width, &height);
io.FontAtlas->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
font->TexID = (void *)(intptr_t)tex_id;
// Store our identifier
io.FontAtlas->TexID = (void *)(intptr_t)tex_id;
}
void InitImGui()
@ -277,10 +282,7 @@ void InitImGui()
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Load font (optionally load a custom TTF font)
//io.Font->LoadFromFileTTF("myfont.ttf", font_size_px, ImFont::GetGlyphRangesDefault());
//io.Font->DisplayOffset.y += 1.0f;
LoadFontTexture(io.Font);
LoadFontTexture();
}
void UpdateImGui()

View File

@ -145,20 +145,25 @@ void InitGL()
glewInit();
}
void LoadFontTexture(ImFont* font)
void LoadFontTexture()
{
ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font = io.FontAtlas->AddFontDefault();
//ImFont* my_font2 = io.FontAtlas->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 20.0f, ImFontAtlas::GetGlyphRangesJapanese());
unsigned char* pixels;
int width, height;
font->GetTextureDataAlpha8(&pixels, &width, &height);
io.FontAtlas->GetTexDataAsAlpha8(&pixels, &width, &height);
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
font->TexID = (void *)(intptr_t)tex_id;
// Store our identifier
io.FontAtlas->TexID = (void *)(intptr_t)tex_id;
}
void InitImGui()
@ -186,11 +191,6 @@ void InitImGui()
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Load font (optionally load a custom TTF font)
//io.Font->LoadFromFileTTF("myfont.ttf", font_size_px, ImFont::GetGlyphRangesDefault());
//io.Font->DisplayOffset.y += 1.0f;
LoadFontTexture(io.Font);
}
void UpdateImGui()

583
imgui.cpp
View File

@ -432,11 +432,9 @@ ImGuiStyle::ImGuiStyle()
Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
}
// We statically allocate a default font storage for the user.
// This allows the user to avoid newing the default font, while keeping IO.Font a pointer which is easy to swap if needed.
// We cannot new() the font because user may override MemAllocFn after the ImGuiIO() constructor is called.
// For the same reason we cannot call LoadDefault() on the font by default, but it is called by GetTextureData*() API.
static ImFont GDefaultStaticFont;
// Statically allocated font atlas. This is merely a maneuver to keep its definition at the bottom of the .H file.
// Because we cannot new() at this point (before users may define IO.MemAllocFn)
static ImFontAtlas GDefaultFontAtlas;
ImGuiIO::ImGuiIO()
{
@ -446,7 +444,7 @@ ImGuiIO::ImGuiIO()
IniSavingRate = 5.0f;
IniFilename = "imgui.ini";
LogFilename = "imgui_log.txt";
Font = &GDefaultStaticFont;
FontAtlas = &GDefaultFontAtlas;
FontGlobalScale = 1.0f;
FontAllowUserScaling = false;
MousePos = ImVec2(-1,-1);
@ -1525,9 +1523,9 @@ void ImGui::NewFrame()
// Check user data
IM_ASSERT(g.IO.DeltaTime > 0.0f);
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f);
IM_ASSERT(g.IO.RenderDrawListsFn != NULL); // Must be implemented
IM_ASSERT(g.IO.Font); // Font not created
IM_ASSERT(g.IO.Font->IsLoaded()); // Font not loaded
IM_ASSERT(g.IO.RenderDrawListsFn != NULL); // Must be implemented
IM_ASSERT(g.IO.FontAtlas->IsBuilt()); // Font not created. Did you call io.FontAtlas->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
IM_ASSERT(g.IO.FontAtlas->Fonts[0]->IsLoaded()); // Font not created. Did you call io.FontAtlas->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
if (!g.Initialized)
{
@ -1540,7 +1538,7 @@ void ImGui::NewFrame()
g.Initialized = true;
}
SetFont(g.IO.Font);
SetFont(g.IO.FontAtlas->Fonts[0]);
g.Time += g.IO.DeltaTime;
g.FrameCount += 1;
@ -1694,15 +1692,7 @@ void ImGui::Shutdown()
fclose(g.LogFile);
g.LogFile = NULL;
}
if (g.IO.Font)
{
if (g.IO.Font != &GDefaultStaticFont)
{
g.IO.Font->~ImFont();
ImGui::MemFree(g.IO.Font);
}
g.IO.Font = NULL;
}
g.IO.FontAtlas->Clear();
if (g.PrivateClipboard)
{
@ -2372,7 +2362,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
if (first_begin_of_the_frame)
{
window->DrawList->Clear();
window->DrawList->PushTextureID(g.Font->TexID);
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
window->Visible = true;
// New windows appears in front
@ -2685,7 +2675,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
else
{
// Short path when we do multiple Begin in the same frame.
window->DrawList->PushTextureID(g.Font->TexID);
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
// Outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
@ -2798,10 +2788,11 @@ static void SetFont(ImFont* font)
{
ImGuiState& g = GImGui;
IM_ASSERT(font && font->IsLoaded());
IM_ASSERT(font->Scale > 0.0f);
g.Font = font;
g.FontSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale;
g.FontTexUvWhitePixel = g.Font->TexUvWhitePixel;
g.FontTexUvWhitePixel = g.Font->ContainerAtlas->TexUvWhitePixel;
g.Font->FallbackGlyph = NULL;
g.Font->FallbackGlyph = g.Font->FindGlyph(g.Font->FallbackChar);
}
@ -2810,9 +2801,12 @@ void ImGui::PushFont(ImFont* font)
{
ImGuiState& g = GImGui;
if (!font)
font = g.IO.FontAtlas->Fonts[0];
SetFont(font);
g.FontStack.push_back(font);
g.CurrentWindow->DrawList->PushTextureID(font->TexID);
g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
}
void ImGui::PopFont()
@ -2821,7 +2815,7 @@ void ImGui::PopFont()
g.CurrentWindow->DrawList->PopTextureID();
g.FontStack.pop_back();
SetFont(g.FontStack.empty() ? g.IO.Font : g.FontStack.back());
SetFont(g.FontStack.empty() ? g.IO.FontAtlas->Fonts[0] : g.FontStack.back());
}
void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
@ -6216,7 +6210,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32
if (text_end == NULL)
text_end = text_begin + strlen(text_begin);
IM_ASSERT(font->TexID == texture_id_stack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
IM_ASSERT(font->ContainerAtlas->TexID == texture_id_stack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
// reserve vertices for worse case
const unsigned int char_count = (unsigned int)(text_end - text_begin);
@ -6255,29 +6249,80 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im
}
//-----------------------------------------------------------------------------
// ImBitmapFont
// ImFontAtlias
//-----------------------------------------------------------------------------
ImFont::ImFont()
struct ImFontAtlas::ImFontAtlasData
{
Scale = 1.0f;
FallbackChar = (ImWchar)'?';
// Input
ImFont* OutFont; // Load into this font
void* TTFData; // TTF data, we own the memory
size_t TTFDataSize; // TTF data size, in bytes
float SizePixels; // Desired output size, in pixels
const ImWchar* GlyphRanges; // List of Unicode range (2 value per range, values are inclusive, zero-terminated list)
int FontNo; // Index of font within .TTF file (0)
// Temporary Build Data
stbtt_fontinfo FontInfo;
stbrp_rect* Rects;
ImVector<stbtt_pack_range> Ranges;
};
ImFontAtlas::ImFontAtlas()
{
TexID = NULL;
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
Clear();
TexWidth = TexHeight = 0;
TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0);
}
ImFont::~ImFont()
ImFontAtlas::~ImFontAtlas()
{
Clear();
ClearInputData();
ClearTexData();
}
void ImFont::GetTextureDataAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
void ImFontAtlas::ClearInputData()
{
// Lazily load default font
if (!IsLoaded())
LoadDefault();
for (size_t i = 0; i < InputData.size(); i++)
{
if (InputData[i]->TTFData)
ImGui::MemFree(InputData[i]->TTFData);
ImGui::MemFree(InputData[i]);
}
InputData.clear();
}
void ImFontAtlas::ClearTexData()
{
if (TexPixelsAlpha8)
ImGui::MemFree(TexPixelsAlpha8);
if (TexPixelsRGBA32)
ImGui::MemFree(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
}
void ImFontAtlas::ClearFonts()
{
for (size_t i = 0; i < Fonts.size(); i++)
{
Fonts[i]->~ImFont();
ImGui::MemFree(Fonts[i]);
}
Fonts.clear();
}
void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
{
// Lazily build
if (TexPixelsAlpha8 == NULL)
{
if (InputData.empty())
AddFontDefault();
Build();
}
*out_pixels = TexPixelsAlpha8;
if (out_width) *out_width = TexWidth;
@ -6285,14 +6330,14 @@ void ImFont::GetTextureDataAlpha8(unsigned char** out_pixels, int* out_width,
if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
}
void ImFont::GetTextureDataRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
{
// Lazily convert to RGBA32 format
// Although it is likely to be the most commonly used format, our font rendering is 8 bpp
if (!TexPixelsRGBA32)
{
unsigned char* pixels;
GetTextureDataAlpha8(&pixels, NULL, NULL);
GetTexDataAsAlpha8(&pixels, NULL, NULL);
TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc(TexWidth * TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
@ -6306,33 +6351,251 @@ void ImFont::GetTextureDataRGBA32(unsigned char** out_pixels, int* out_width,
if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
}
void ImFont::ClearTextureData()
static void GetDefaultCompressedFontDataTTF(const void** ttf_compressed_data, unsigned int* ttf_compressed_size);
static unsigned int stb_decompress_length(unsigned char *input);
static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
// Load embedded ProggyClean.ttf at size 13
ImFont* ImFontAtlas::AddFontDefault()
{
if (TexPixelsAlpha8)
ImGui::MemFree(TexPixelsAlpha8);
if (TexPixelsRGBA32)
ImGui::MemFree(TexPixelsRGBA32);
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
// Get compressed data
unsigned int ttf_compressed_size;
const void* ttf_compressed;
GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size);
// Decompress
const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)ttf_compressed);
unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
stb_decompress(buf_decompressed, (unsigned char*)ttf_compressed, ttf_compressed_size);
// Add
ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, 13.0f, ImFontAtlas::GetGlyphRangesDefault(), 0);
font->DisplayOffset.y += 1;
return font;
}
ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges, int font_no)
{
void* data = NULL;
size_t data_size = 0;
if (!ImLoadFileToMemory(filename, "rb", (void**)&data, &data_size))
return NULL;
// Add
ImFont* font = AddFontFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no);
return font;
}
// NB: ownership of 'data' is given to ImFontAtlas which will clear it.
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
{
// Create new font
ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
new (font) ImFont();
Fonts.push_back(font);
// Add to build list
ImFontAtlasData* data = (ImFontAtlasData*)ImGui::MemAlloc(sizeof(ImFontAtlasData));
memset(data, 0, sizeof(ImFontAtlasData));
data->OutFont = font;
data->TTFData = in_ttf_data;
data->TTFDataSize = in_ttf_data_size;
data->SizePixels = size_pixels;
data->GlyphRanges = glyph_ranges;
data->FontNo = 0;
InputData.push_back(data);
// Invalidate texture
ClearTexData();
return font;
}
bool ImFontAtlas::Build()
{
IM_ASSERT(InputData.size() > 0);
TexID = NULL;
TexWidth = TexHeight = 0;
TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0);
ClearTexData();
// Initialize font information early (so we can error without any cleanup) + count glyphs
int total_glyph_count = 0;
for (size_t input_i = 0; input_i < InputData.size(); input_i++)
{
ImFontAtlasData& data = *InputData[input_i];
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)data.TTFData, data.FontNo);
IM_ASSERT(font_offset >= 0);
if (!stbtt_InitFont(&data.FontInfo, (unsigned char*)data.TTFData, font_offset))
return false;
for (const ImWchar* in_range = InputData[input_i]->GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
total_glyph_count += (in_range[1] - in_range[0]) + 1;
}
// Start packing
TexWidth = (total_glyph_count > 3000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512; // Width doesn't actually matters.
TexHeight = 0;
const int max_tex_height = 1024*32;
stbtt_pack_context spc;
int ret = stbtt_PackBegin(&spc, NULL, TexWidth, max_tex_height, 0, 1, NULL);
IM_ASSERT(ret);
stbtt_PackSetOversampling(&spc, 1, 1);
// Pack our extra data rectangle first, so it will be on the upper-left corner of our texture (UV will have small values).
stbrp_rect extra_rect;
extra_rect.w = 16;
extra_rect.h = 16;
stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1);
TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y);
// First pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only)
int tex_height = extra_rect.y + extra_rect.h;
for (size_t input_i = 0; input_i < InputData.size(); input_i++)
{
ImFontAtlasData& data = *InputData[input_i];
if (!data.GlyphRanges)
data.GlyphRanges = ImFontAtlas::GetGlyphRangesDefault();
// Setup ranges
int glyph_count = 0;
int glyph_ranges_count = 0;
for (const ImWchar* in_range = data.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
{
glyph_count += (in_range[1] - in_range[0]) + 1;
glyph_ranges_count++;
}
data.Ranges.resize(glyph_ranges_count);
for (size_t i = 0; i < data.Ranges.size(); i++)
{
stbtt_pack_range& range = data.Ranges[i];
range.font_size = data.SizePixels;
const ImWchar* in_range = &data.GlyphRanges[i * 2];
range.first_unicode_char_in_range = in_range[0];
range.num_chars_in_range = (in_range[1] - in_range[0]) + 1;
// Allocate characters and flag as not packed
// FIXME-OPT: Loose ranges will incur lots of allocations. Allocate all contiguous in loop above.
range.chardata_for_range = (stbtt_packedchar*)ImGui::MemAlloc(range.num_chars_in_range * sizeof(stbtt_packedchar));
for (int j = 0; j < range.num_chars_in_range; ++j)
range.chardata_for_range[j].x0 = range.chardata_for_range[j].y0 = range.chardata_for_range[j].x1 = range.chardata_for_range[j].y1 = 0;
}
// Pack
data.Rects = (stbrp_rect*)ImGui::MemAlloc(sizeof(stbrp_rect) * glyph_count);
IM_ASSERT(data.Rects);
const int n = stbtt_PackFontRangesGatherRects(&spc, &data.FontInfo, data.Ranges.begin(), data.Ranges.size(), data.Rects);
stbrp_pack_rects((stbrp_context*)spc.pack_info, data.Rects, n);
// Extend texture height
for (int i = 0; i < n; i++)
if (data.Rects[i].was_packed)
tex_height = ImMax(tex_height, data.Rects[i].y + data.Rects[i].h);
}
// Create texture
TexHeight = ImUpperPowerOfTwo(tex_height);
TexPixelsAlpha8 = (unsigned char*)ImGui::MemRealloc(TexPixelsAlpha8, TexWidth * TexHeight);
memset(TexPixelsAlpha8, 0, TexWidth * TexHeight);
spc.pixels = TexPixelsAlpha8;
spc.height = TexHeight;
// Second pass: render characters
for (size_t input_i = 0; input_i < InputData.size(); input_i++)
{
ImFontAtlasData& data = *InputData[input_i];
ret = stbtt_PackFontRangesRenderIntoRects(&spc, &data.FontInfo, data.Ranges.begin(), data.Ranges.size(), data.Rects);
ImGui::MemFree(data.Rects);
data.Rects = NULL;
}
// End packing
stbtt_PackEnd(&spc);
// Third pass: setup ImFont and glyphs for runtime
for (size_t input_i = 0; input_i < InputData.size(); input_i++)
{
ImFontAtlasData& data = *InputData[input_i];
data.OutFont->ContainerAtlas = this;
data.OutFont->FontSize = data.SizePixels;
const float font_scale = stbtt_ScaleForPixelHeight(&data.FontInfo, data.SizePixels);
int font_ascent, font_descent, font_line_gap;
stbtt_GetFontVMetrics(&data.FontInfo, &font_ascent, &font_descent, &font_line_gap);
const float uv_scale_x = 1.0f / TexWidth;
const float uv_scale_y = 1.0f / TexHeight;
const int character_spacing_x = 1;
for (size_t i = 0; i < data.Ranges.size(); i++)
{
stbtt_pack_range& range = data.Ranges[i];
for (int char_idx = 0; char_idx < range.num_chars_in_range; char_idx += 1)
{
const int codepoint = range.first_unicode_char_in_range + char_idx;
const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
continue;
data.OutFont->Glyphs.resize(data.OutFont->Glyphs.size() + 1);
ImFont::Glyph& glyph = data.OutFont->Glyphs.back();
glyph.Codepoint = (ImWchar)codepoint;
glyph.Width = pc.x1 - pc.x0 + 1;
glyph.Height = pc.y1 - pc.y0 + 1;
glyph.XOffset = (signed short)(pc.xoff);
glyph.YOffset = (signed short)(pc.yoff) + (int)(font_ascent * font_scale);
glyph.XAdvance = (signed short)(pc.xadvance + character_spacing_x); // Bake spacing into XAdvance
glyph.U0 = ((float)pc.x0 - 0.5f) * uv_scale_x;
glyph.V0 = ((float)pc.y0 - 0.5f) * uv_scale_y;
glyph.U1 = ((float)pc.x0 - 0.5f + glyph.Width) * uv_scale_x;
glyph.V1 = ((float)pc.y0 - 0.5f + glyph.Height) * uv_scale_y;
}
}
data.OutFont->BuildLookupTable();
// Cleanup temporary
for (size_t i = 0; i < data.Ranges.size(); i++)
ImGui::MemFree(data.Ranges[i].chardata_for_range);
data.Ranges.clear();
}
// Draw white pixel into texture and make UV points to it
TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF;
TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight);
ClearInputData();
return true;
}
//-----------------------------------------------------------------------------
// ImFont
//-----------------------------------------------------------------------------
ImFont::ImFont()
{
Scale = 1.0f;
FallbackChar = (ImWchar)'?';
Clear();
}
ImFont::~ImFont()
{
Clear();
}
void ImFont::Clear()
{
FontSize = 0.0f;
DisplayOffset = ImVec2(-0.5f, 0.5f);
ClearTextureData();
TexID = NULL;
TexWidth = TexHeight = 0;
TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0);
ContainerAtlas = NULL;
Glyphs.clear();
IndexLookup.clear();
FallbackGlyph = NULL;
}
// Retrieve list of range (2 int per range, values are inclusive)
const ImWchar* ImFont::GetGlyphRangesDefault()
const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
{
static const ImWchar ranges[] =
{
@ -6342,7 +6605,7 @@ const ImWchar* ImFont::GetGlyphRangesDefault()
return &ranges[0];
}
const ImWchar* ImFont::GetGlyphRangesChinese()
const ImWchar* ImFontAtlas::GetGlyphRangesChinese()
{
static const ImWchar ranges[] =
{
@ -6355,7 +6618,7 @@ const ImWchar* ImFont::GetGlyphRangesChinese()
return &ranges[0];
}
const ImWchar* ImFont::GetGlyphRangesJapanese()
const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
{
// Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1.
// This encoding helps us reduce the source code size.
@ -6415,167 +6678,6 @@ const ImWchar* ImFont::GetGlyphRangesJapanese()
return &ranges[0];
}
static void GetDefaultCompressedFontDataTTF(const void** ttf_compressed_data, unsigned int* ttf_compressed_size);
static unsigned int stb_decompress_length(unsigned char *input);
static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
// Load embedded ProggyClean.ttf at size 13
bool ImFont::LoadDefault()
{
// Get compressed data
unsigned int ttf_compressed_size;
const void* ttf_compressed;
GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size);
// Decompress
const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)ttf_compressed);
unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
stb_decompress(buf_decompressed, (unsigned char*)ttf_compressed, ttf_compressed_size);
// Load TTF
const bool ret = LoadFromMemoryTTF((void *)buf_decompressed, buf_decompressed_size, 13.0f, ImFont::GetGlyphRangesDefault(), 0);
ImGui::MemFree(buf_decompressed);
DisplayOffset.y += 1;
return ret;
}
bool ImFont::LoadFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges, int font_no)
{
void* data = NULL;
size_t data_size = 0;
if (!ImLoadFileToMemory(filename, "rb", (void**)&data, &data_size))
return false;
const bool ret = LoadFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no);
ImGui::MemFree(data);
return ret;
}
bool ImFont::LoadFromMemoryTTF(const void* data, size_t data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
{
Clear();
if (!glyph_ranges)
glyph_ranges = GetGlyphRangesDefault();
// Initialize font information
stbtt_fontinfo ttf_info;
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)data, font_no);
IM_ASSERT(font_offset >= 0);
if (!stbtt_InitFont(&ttf_info, (unsigned char*)data, font_offset))
return false;
// Setup ranges
int glyph_count = 0;
int glyph_ranges_count = 0;
for (const ImWchar* in_range = glyph_ranges; in_range[0] && in_range[1]; in_range += 2)
{
glyph_count += (in_range[1] - in_range[0]) + 1;
glyph_ranges_count++;
}
ImVector<stbtt_pack_range> ranges;
ranges.resize(glyph_ranges_count);
for (size_t i = 0; i < ranges.size(); i++)
{
stbtt_pack_range& range = ranges[i];
range.font_size = size_pixels;
const ImWchar* in_range = &glyph_ranges[i * 2];
range.first_unicode_char_in_range = in_range[0];
range.num_chars_in_range = (in_range[1] - in_range[0]) + 1;
range.chardata_for_range = (stbtt_packedchar*)ImGui::MemAlloc(range.num_chars_in_range * sizeof(stbtt_packedchar));
}
{
TexWidth = (glyph_count > 1000) ? 1024 : 512; // Width doesn't really matters.
TexHeight = 0;
const int max_tex_height = 1024*32;
stbtt_pack_context spc;
int ret = stbtt_PackBegin(&spc, NULL, TexWidth, max_tex_height, 0, 1, NULL);
IM_ASSERT(ret);
stbtt_PackSetOversampling(&spc, 1, 1);
// Flag all characters as not packed
for (size_t i = 0; i < ranges.size(); ++i)
for (int j = 0; j < ranges[i].num_chars_in_range; ++j)
ranges[i].chardata_for_range[j].x0 = ranges[i].chardata_for_range[j].y0 = ranges[i].chardata_for_range[j].x1 = ranges[i].chardata_for_range[j].y1 = 0;
// Pack our extra data rectangle first, so it will be on the upper-left corner of our texture (UV will have small values).
stbrp_rect extra_rect;
extra_rect.w = 16;
extra_rect.h = 16;
stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1);
TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y);
// Pack
stbrp_rect* rects = (stbrp_rect*)ImGui::MemAlloc(sizeof(*rects) * glyph_count);
IM_ASSERT(rects);
const int n = stbtt_PackFontRangesGatherRects(&spc, &ttf_info, ranges.begin(), ranges.size(), rects);
stbrp_pack_rects((stbrp_context*)spc.pack_info, rects, n);
// Create texture
int tex_h = 0;
for (int i = 0; i < n; i++)
if (rects[i].was_packed)
tex_h = ImMax(tex_h, rects[i].y + rects[i].h);
TexHeight = ImUpperPowerOfTwo(tex_h);
TexPixelsAlpha8 = (unsigned char*)ImGui::MemRealloc(TexPixelsAlpha8, TexWidth * TexHeight);
memset(TexPixelsAlpha8, 0, TexWidth * TexHeight);
// Render characters
spc.pixels = TexPixelsAlpha8;
spc.height = TexHeight;
ret = stbtt_PackFontRangesRenderIntoRects(&spc, &ttf_info, ranges.begin(), ranges.size(), rects);
stbtt_PackEnd(&spc);
ImGui::MemFree(rects);
}
// Setup glyphs for runtime
FontSize = size_pixels;
const float font_scale = stbtt_ScaleForPixelHeight(&ttf_info, size_pixels);
int font_ascent, font_descent, font_line_gap;
stbtt_GetFontVMetrics(&ttf_info, &font_ascent, &font_descent, &font_line_gap);
const float uv_scale_x = 1.0f / TexWidth;
const float uv_scale_y = 1.0f / TexHeight;
const int character_spacing_x = 1;
for (size_t i = 0; i < ranges.size(); i++)
{
stbtt_pack_range& range = ranges[i];
for (int char_idx = 0; char_idx < range.num_chars_in_range; char_idx += 1)
{
const int codepoint = range.first_unicode_char_in_range + char_idx;
const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
continue;
Glyphs.resize(Glyphs.size() + 1);
ImFont::Glyph& glyph = Glyphs.back();
glyph.Codepoint = (ImWchar)codepoint;
glyph.Width = pc.x1 - pc.x0 + 1;
glyph.Height = pc.y1 - pc.y0 + 1;
glyph.XOffset = (signed short)(pc.xoff);
glyph.YOffset = (signed short)(pc.yoff) + (int)(font_ascent * font_scale);
glyph.XAdvance = (signed short)(pc.xadvance + character_spacing_x); // Bake spacing into XAdvance
glyph.U0 = ((float)pc.x0 - 0.5f) * uv_scale_x;
glyph.V0 = ((float)pc.y0 - 0.5f) * uv_scale_y;
glyph.U1 = ((float)pc.x0 - 0.5f + glyph.Width) * uv_scale_x;
glyph.V1 = ((float)pc.y0 - 0.5f + glyph.Height) * uv_scale_y;
}
}
BuildLookupTable();
// Cleanup temporary
for (size_t i = 0; i < ranges.size(); i++)
ImGui::MemFree(ranges[i].chardata_for_range);
// Draw white pixel and make UV points to it
TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF;
TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight);
return true;
}
void ImFont::BuildLookupTable()
{
int max_codepoint = 0;
@ -7315,20 +7417,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::TreePop();
}
// Font scaling options
// Note that those are not actually part of the style.
if (ImGui::TreeNode("Font"))
{
static float window_scale = 1.0f;
ImFont* font = ImGui::GetIO().Font;
ImGui::Text("Base Font Size: %.2f", font->FontSize);
ImGui::SliderFloat("window scale", &window_scale, 0.3f, 2.0f, "%.1f"); // scale only this window
ImGui::SliderFloat("font scale", &font->Scale, 0.3f, 2.0f, "%.1f"); // scale only this font
ImGui::SliderFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.3f, 2.0f, "%.1f"); // scale everything
ImGui::SetWindowFontScale(window_scale);
ImGui::TreePop();
}
ImGui::PopItemWidth();
}
@ -7375,12 +7463,38 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::Checkbox("no scrollbar", &no_scrollbar);
ImGui::SliderFloat("fill alpha", &fill_alpha, 0.0f, 1.0f);
if (ImGui::TreeNode("Style Editor"))
if (ImGui::TreeNode("Style"))
{
ImGui::ShowStyleEditor();
ImGui::TreePop();
}
if (ImGui::TreeNode("Fonts"))
{
ImGui::TextWrapped("Tip: Load fonts with GetIO().FontAtlas->AddFontFromFileTTF().");
for (size_t i = 0; i < ImGui::GetIO().FontAtlas->Fonts.size(); i++)
{
ImFont* font = ImGui::GetIO().FontAtlas->Fonts[i];
ImGui::BulletText("Font %d: %.2f pixels, %d glyphs", i, font->FontSize, font->Glyphs.size());
ImGui::TreePush((void*)i);
ImGui::PushFont(font);
ImGui::Text("The quick brown fox jumps over the lazy dog");
ImGui::PopFont();
if (i > 0 && ImGui::Button("Set as default"))
{
ImGui::GetIO().FontAtlas->Fonts[i] = ImGui::GetIO().FontAtlas->Fonts[0];
ImGui::GetIO().FontAtlas->Fonts[0] = font;
}
ImGui::SliderFloat("font scale", &font->Scale, 0.3f, 2.0f, "%.1f"); // scale only this font
ImGui::TreePop();
}
static float window_scale = 1.0f;
ImGui::SliderFloat("this window scale", &window_scale, 0.3f, 2.0f, "%.1f"); // scale only this window
ImGui::SliderFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.3f, 2.0f, "%.1f"); // scale everything
ImGui::SetWindowFontScale(window_scale);
ImGui::TreePop();
}
if (ImGui::TreeNode("Logging"))
{
ImGui::LogButtons();
@ -7475,9 +7589,10 @@ void ImGui::ShowTestWindow(bool* opened)
{
ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!");
ImVec2 tex_screen_pos = ImGui::GetCursorScreenPos();
float tex_w = (float)ImGui::GetIO().Font->TexWidth;
float tex_h = (float)ImGui::GetIO().Font->TexHeight;
ImGui::Image(ImGui::GetIO().Font->TexID, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), 0xFFFFFFFF, 0x999999FF);
float tex_w = (float)ImGui::GetIO().FontAtlas->TexWidth;
float tex_h = (float)ImGui::GetIO().FontAtlas->TexHeight;
ImTextureID tex_id = ImGui::GetIO().FontAtlas->TexID;
ImGui::Image(tex_id, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), 0xFFFFFFFF, 0x999999FF);
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
@ -7488,7 +7603,7 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::Text("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz);
ImVec2 uv0 = ImVec2((focus_x) / tex_w, (focus_y) / tex_h);
ImVec2 uv1 = ImVec2((focus_x + focus_sz) / tex_w, (focus_y + focus_sz) / tex_h);
ImGui::Image(ImGui::GetIO().Font->TexID, ImVec2(128,128), uv0, uv1, 0xFFFFFFFF, 0x999999FF);
ImGui::Image(tex_id, ImVec2(128,128), uv0, uv1, 0xFFFFFFFF, 0x999999FF);
ImGui::EndTooltip();
}
ImGui::TreePop();

148
imgui.h
View File

@ -8,6 +8,7 @@
struct ImDrawList;
struct ImFont;
struct ImFontAtlas;
struct ImGuiAabb;
struct ImGuiIO;
struct ImGuiStorage;
@ -176,7 +177,7 @@ namespace ImGui
IMGUI_API ImGuiStorage* GetStateStorage();
// Parameters stacks (shared)
IMGUI_API void PushFont(ImFont* font);
IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font
IMGUI_API void PopFont();
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col);
IMGUI_API void PopStyleColor(int count = 1);
@ -483,19 +484,19 @@ struct ImGuiIO
// Settings (fill once) // Default value:
//------------------------------------------------------------------
ImVec2 DisplaySize; // <unset> // Display size, in pixels. For clamping windows positions.
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
float IniSavingRate; // = 5.0f // Maximum time between saving .ini file, in seconds.
const char* IniFilename; // = "imgui.ini" // Path to .ini file. NULL to disable .ini saving.
const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
int KeyMap[ImGuiKey_COUNT]; // <unset> // Map of indices into the KeysDown[512] entries array
ImFont* Font; // <auto> // Font (also see 'Settings' fields inside ImFont structure for details)
float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
ImVec2 DisplaySize; // <unset> // Display size, in pixels. For clamping windows positions.
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
float IniSavingRate; // = 5.0f // Maximum time between saving .ini file, in seconds.
const char* IniFilename; // = "imgui.ini" // Path to .ini file. NULL to disable .ini saving.
const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
int KeyMap[ImGuiKey_COUNT]; // <unset> // Map of indices into the KeysDown[512] entries array
void* UserData; // = NULL // Store your own data for retrieval by callbacks.
void* UserData; // = NULL // Store your own data for retrieval by callbacks.
ImFontAtlas* FontAtlas; // <auto> // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array.
float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
//------------------------------------------------------------------
// User Functions
@ -553,7 +554,7 @@ struct ImGuiIO
float MouseDownTime[5];
float KeysDownTime[512];
IMGUI_API ImGuiIO();
IMGUI_API ImGuiIO();
};
//-----------------------------------------------------------------------------
@ -746,6 +747,57 @@ struct ImDrawList
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col);
};
// Load and rasterize multiple TTF fonts into a same texture.
// We also add custom graphic data into the texture that serves for ImGui.
// Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering.
// The simple use case, if you don't intent to load custom or multiple fonts, is:
// 1. GetTexDataAsRGBA32() or GetTexDataAsAlpha8() // to obtain pixels
// 2. <upload the texture to graphics memory>
// 3. SetTexID(my_engine_id); // use the pointer/id to your texture in your engine format
// 4. ClearPixelsData() // to save memory
struct ImFontAtlas
{
// Methods
IMGUI_API ImFontAtlas();
IMGUI_API ~ImFontAtlas();
IMGUI_API ImFont* AddFontDefault();
IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
IMGUI_API ImFont* AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory.
IMGUI_API bool Build();
IMGUI_API void ClearInputData();
IMGUI_API void ClearFonts();
IMGUI_API void ClearTexData(); // Saves RAM once the texture has been copied to graphics memory.
IMGUI_API void Clear() { ClearInputData(); ClearTexData(); ClearFonts(); }
IMGUI_API bool IsBuilt() const { return !Fonts.empty(); }
// Methods: Retrieve texture data
// User is in charge of copying the pixels into graphics memory, then call SetTextureUserID()
// 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 high compatibility, but note that all RGB pixels are white, so 75% of the memory is wasted.
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 GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
IMGUI_API void SetTexID(void* id) { TexID = id; }
// Static helper: Retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
static IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin
static IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
static IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs
// Members
// Access texture data via GetTextureData*() calls which will setup a default font for you.
void* TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It ia passed back to you during rendering.
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
int TexWidth;
int TexHeight;
ImVec2 TexExtraDataPos; // Position of our rectangle where we draw non-font graphics
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block)
ImVector<ImFont*> Fonts;
struct ImFontAtlasData;
ImVector<ImFontAtlasData*> InputData; // Internal data
};
// TTF font loading and rendering
// - ImGui automatically loads a default embedded font for you
// - Call GetTextureData() to retrieve pixels data so you can upload the texture to your graphics system.
@ -753,55 +805,13 @@ struct ImDrawList
// (NB: kerning isn't supported. At the moment some ImGui code does per-character CalcTextSize calls, need something more state-ful)
struct ImFont
{
// Settings
// Members: Settings
float FontSize; // <user set> // Height of characters, set during loading (don't change after loading)
float Scale; // = 1.0f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale()
ImVec2 DisplayOffset; // = (0.0f,0.0f) // Offset font rendering by xx pixels
ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found.
ImTextureID TexID; // = 0 // After loading texture, store your texture handle here (ignore if you aren't using multiple fonts/textures)
// Retrieve texture data
// User is in charge of copying the pixels into graphics memory, then set 'TexID'.
// RGBA32 format is provided for convenience and high compatibility, but note that all RGB pixels are white.
// If you intend to use large font it may be pref
// NB: the data is invalidated as soon as you call a Load* function.
IMGUI_API void GetTextureDataRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel
IMGUI_API void GetTextureDataAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
IMGUI_API void ClearTextureData(); // Save RAM once the texture has been copied to graphics memory.
// Methods
IMGUI_API ImFont();
IMGUI_API ~ImFont();
IMGUI_API bool LoadDefault();
IMGUI_API bool LoadFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
IMGUI_API bool LoadFromMemoryTTF(const void* data, size_t data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
IMGUI_API void Clear();
IMGUI_API void BuildLookupTable();
struct Glyph;
IMGUI_API const Glyph* FindGlyph(unsigned short c) const;
IMGUI_API bool IsLoaded() const { return !Glyphs.empty(); }
// Retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
static IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin
static IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
static IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8
IMGUI_API ImVec2 CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL) const; // wchar
IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawVert*& out_vertices, float wrap_width = 0.0f) const;
IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const;
// Texture data
// Access via GetTextureData() which will load the font if not loaded
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
int TexWidth;
int TexHeight;
ImVec2 TexExtraDataPos; // Position of our rectangle where we draw non-font graphics
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block)
// Members: Runtime data
struct Glyph
{
ImWchar Codepoint;
@ -810,11 +820,29 @@ struct ImFont
signed short XOffset, YOffset;
float U0, V0, U1, V1; // Texture coordinates
};
// Runtime data
ImFontAtlas* ContainerAtlas; // What we has been loaded into
ImVector<Glyph> Glyphs;
ImVector<int> IndexLookup;
const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar)
// Methods
IMGUI_API ImFont();
IMGUI_API ~ImFont();
IMGUI_API void Clear();
IMGUI_API void BuildLookupTable();
IMGUI_API const Glyph* FindGlyph(unsigned short c) const;
IMGUI_API bool IsLoaded() const { return ContainerAtlas != NULL; }
IMGUI_API ImTextureID GetTexID() const { IM_ASSERT(ContainerAtlas != NULL); return ContainerAtlas->TexID; }
IMGUI_API int GetTexWidth() const { IM_ASSERT(ContainerAtlas != NULL); return ContainerAtlas->TexWidth; }
IMGUI_API int GetTexHeight() const { IM_ASSERT(ContainerAtlas != NULL); return ContainerAtlas->TexHeight; }
// 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
// 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8
IMGUI_API ImVec2 CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL) const; // wchar
IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawVert*& out_vertices, float wrap_width = 0.0f) const;
IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const;
};
//---- Include imgui_user.h at the end of imgui.h