ImFontAtlas allows loading multiple fonts into same texture. Revamped new init API for 1.30
This commit is contained in:
parent
cb9a3235be
commit
2c31599bcc
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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
583
imgui.cpp
@ -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
148
imgui.h
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user