mirror of
https://github.com/Drezil/imgui.git
synced 2024-12-18 06:06:35 +00:00
Merge branch 'master' into navigation
# Conflicts: # imgui.cpp
This commit is contained in:
commit
0bd15b52a6
13
imgui.cpp
13
imgui.cpp
@ -810,6 +810,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
|
||||
GrabRounding = ImFloor(GrabRounding * scale_factor);
|
||||
DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
|
||||
DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
|
||||
MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
|
||||
}
|
||||
|
||||
ImGuiIO::ImGuiIO()
|
||||
@ -3961,11 +3962,12 @@ void ImGui::Render()
|
||||
{
|
||||
const ImVec2 pos = g.IO.MousePos - offset;
|
||||
const ImTextureID tex_id = g.IO.Fonts->TexID;
|
||||
const float sc = g.Style.MouseCursorScale;
|
||||
g.OverlayDrawList.PushTextureID(tex_id);
|
||||
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
|
||||
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
|
||||
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, uv[2], uv[3], IM_COL32(0,0,0,255)); // Black border
|
||||
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, uv[0], uv[1], IM_COL32(255,255,255,255)); // White fill
|
||||
g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(1,0)*sc, pos+ImVec2(1,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
|
||||
g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(2,0)*sc, pos+ImVec2(2,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow
|
||||
g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[2], uv[3], IM_COL32(0,0,0,255)); // Black border
|
||||
g.OverlayDrawList.AddImage(tex_id, pos, pos + size*sc, uv[0], uv[1], IM_COL32(255,255,255,255)); // White fill
|
||||
g.OverlayDrawList.PopTextureID();
|
||||
}
|
||||
if (!g.OverlayDrawList.VtxBuffer.empty())
|
||||
@ -5728,12 +5730,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
||||
// Position tooltip (always follows mouse)
|
||||
if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
|
||||
{
|
||||
float sc = g.Style.MouseCursorScale;
|
||||
ImVec2 ref_pos = (!g.NavDisableHighlight && g.NavDisableMouseHover) ? NavCalcPreferredMousePos() : g.IO.MousePos;
|
||||
ImRect rect_to_avoid;
|
||||
if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.NavFlags & ImGuiNavFlags_MoveMouse))
|
||||
rect_to_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
|
||||
else
|
||||
rect_to_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24, ref_pos.y + 24); // FIXME-NAV: Completely hard-coded based on expected mouse cursor size. Store boxes in mouse cursor data? Scale? Center on cursor hit-point?
|
||||
rect_to_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
|
||||
window->PosFloat = FindBestWindowPosForPopup(ref_pos, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
|
||||
if (window->AutoPosLastDirection == ImGuiDir_None)
|
||||
window->PosFloat = ref_pos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
|
||||
|
1
imgui.h
1
imgui.h
@ -921,6 +921,7 @@ struct ImGuiStyle
|
||||
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered.
|
||||
ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
|
||||
ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
|
||||
float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
|
||||
bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU.
|
||||
bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||
|
@ -120,9 +120,7 @@ In this document:
|
||||
|
||||
Dear Imgui uses stb_truetype.h to rasterize fonts (with optional oversampling).
|
||||
This technique and implementation are not ideal for fonts rendered at _small sizes_, which may appear a little blurry.
|
||||
There is an implementation of the ImFontAtlas builder using FreeType that you can use:
|
||||
|
||||
https://github.com/ocornut/imgui_club
|
||||
There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder.
|
||||
|
||||
FreeType supports auto-hinting which tends to improve the readability of small fonts.
|
||||
Note that this code currently creates textures that are unoptimally too large (could be fixed with some work)
|
||||
|
126
misc/freetype/README.md
Normal file
126
misc/freetype/README.md
Normal file
@ -0,0 +1,126 @@
|
||||
# imgui_freetype
|
||||
|
||||
This is an attempt to replace stb_truetype (the default imgui's font rasterizer) with FreeType.
|
||||
Currently not optimal and probably has some limitations or bugs.
|
||||
By [Vuhdo](https://github.com/Vuhdo) (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut.
|
||||
|
||||
**Usage**
|
||||
1. Get latest FreeType binaries or build yourself.
|
||||
2. Add imgui_freetype.h/cpp alongside your imgui sources.
|
||||
3. Include imgui_freetype.h after imgui.h.
|
||||
4. Call ImGuiFreeType::BuildFontAtlas() *BEFORE* calling ImFontAtlas::GetTexDataAsRGBA32() or ImFontAtlas::Build() (so normal Build() won't be called):
|
||||
|
||||
```cpp
|
||||
// See ImGuiFreeType::RasterizationFlags
|
||||
unsigned int flags = ImGuiFreeType::DisableHinting;
|
||||
ImGuiFreeType::BuildFontAtlas(io.Fonts, flags);
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
```
|
||||
|
||||
**Test code Usage**
|
||||
```cpp
|
||||
#include "misc/freetype/imgui_freetype.h"
|
||||
#include "misc/freetype/imgui_freetype.cpp"
|
||||
|
||||
// Load various small fonts
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 13.0f);
|
||||
io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 13.0f);
|
||||
io.Fonts->AddFontDefault();
|
||||
|
||||
FreeTypeTest freetype_test;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
if (freetype_test.UpdateRebuild())
|
||||
{
|
||||
// REUPLOAD FONT TEXTURE TO GPU
|
||||
// e.g ImGui_ImplGlfwGL3_InvalidateDeviceObjects() + ImGui_ImplGlfwGL3_CreateDeviceObjects()
|
||||
}
|
||||
ImGui::NewFrame();
|
||||
freetype_test.ShowFreetypeOptionsWindow();
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Test code**
|
||||
```cpp
|
||||
#include "misc/freetype/imgui_freetype.h"
|
||||
#include "misc/freetype/imgui_freetype.cpp"
|
||||
|
||||
struct FreeTypeTest
|
||||
{
|
||||
enum FontBuildMode
|
||||
{
|
||||
FontBuildMode_FreeType,
|
||||
FontBuildMode_Stb,
|
||||
};
|
||||
|
||||
FontBuildMode BuildMode;
|
||||
bool WantRebuild;
|
||||
float FontsMultiply;
|
||||
unsigned int FontsFlags;
|
||||
|
||||
FreeTypeTest()
|
||||
{
|
||||
BuildMode = FontBuildMode_FreeType;
|
||||
WantRebuild = true;
|
||||
FontsMultiply = 1.0f;
|
||||
FontsFlags = 0;
|
||||
}
|
||||
|
||||
// Call _BEFORE_ NewFrame()
|
||||
bool UpdateRebuild()
|
||||
{
|
||||
if (!WantRebuild)
|
||||
return false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
for (int n = 0; n < io.Fonts->Fonts.Size; n++)
|
||||
{
|
||||
io.Fonts->Fonts[n]->ConfigData->RasterizerMultiply = FontsMultiply;
|
||||
io.Fonts->Fonts[n]->ConfigData->RasterizerFlags = (BuildMode == FontBuildMode_FreeType) ? FontsFlags : 0x00;
|
||||
}
|
||||
if (BuildMode == FontBuildMode_FreeType)
|
||||
ImGuiFreeType::BuildFontAtlas(io.Fonts, FontsFlags);
|
||||
else if (BuildMode == FontBuildMode_Stb)
|
||||
io.Fonts->Build();
|
||||
WantRebuild = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call to draw interface
|
||||
void ShowFreetypeOptionsWindow()
|
||||
{
|
||||
ImGui::Begin("FreeType Options");
|
||||
ImGui::ShowFontSelector("Fonts");
|
||||
WantRebuild |= ImGui::RadioButton("FreeType", (int*)&BuildMode, FontBuildMode_FreeType);
|
||||
ImGui::SameLine();
|
||||
WantRebuild |= ImGui::RadioButton("Stb (Default)", (int*)&BuildMode, FontBuildMode_Stb);
|
||||
WantRebuild |= ImGui::DragFloat("Multiply", &FontsMultiply, 0.001f, 0.0f, 2.0f);
|
||||
if (BuildMode == FontBuildMode_FreeType)
|
||||
{
|
||||
WantRebuild |= ImGui::CheckboxFlags("NoHinting", &FontsFlags, ImGuiFreeType::NoHinting);
|
||||
WantRebuild |= ImGui::CheckboxFlags("NoAutoHint", &FontsFlags, ImGuiFreeType::NoAutoHint);
|
||||
WantRebuild |= ImGui::CheckboxFlags("ForceAutoHint", &FontsFlags, ImGuiFreeType::ForceAutoHint);
|
||||
WantRebuild |= ImGui::CheckboxFlags("LightHinting", &FontsFlags, ImGuiFreeType::LightHinting);
|
||||
WantRebuild |= ImGui::CheckboxFlags("MonoHinting", &FontsFlags, ImGuiFreeType::MonoHinting);
|
||||
WantRebuild |= ImGui::CheckboxFlags("Bold", &FontsFlags, ImGuiFreeType::Bold);
|
||||
WantRebuild |= ImGui::CheckboxFlags("Oblique", &FontsFlags, ImGuiFreeType::Oblique);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Known issues**
|
||||
- Output texture has excessive resolution (lots of vertical waste)
|
||||
- FreeType's memory allocator is not overridden.
|
||||
|
||||
**Obligatory comparison screenshots**
|
||||
|
||||
Using Windows built-in segoeui.ttf font. Open in new browser tabs, view at 1080p+.
|
||||
|
||||
![freetype rasterizer](https://raw.githubusercontent.com/wiki/ocornut/imgui_club/images/freetype_20170817.png)
|
||||
|
370
misc/freetype/imgui_freetype.cpp
Normal file
370
misc/freetype/imgui_freetype.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
|
||||
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||
// Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut
|
||||
|
||||
// Changelog:
|
||||
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
||||
// - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
|
||||
// - v0.52: (2017/09/26) fixes for imgui internal changes
|
||||
// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement)
|
||||
// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member
|
||||
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
||||
|
||||
// TODO:
|
||||
// - Output texture has excessive resolution (lots of vertical waste)
|
||||
// - FreeType's memory allocator is not overridden.
|
||||
|
||||
#include "imgui_freetype.h"
|
||||
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
||||
#include <stdint.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#include FT_SYNTHESIS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// Glyph metrics:
|
||||
// --------------
|
||||
//
|
||||
// xmin xmax
|
||||
// | |
|
||||
// |<-------- width -------->|
|
||||
// | |
|
||||
// | +-------------------------+----------------- ymax
|
||||
// | | ggggggggg ggggg | ^ ^
|
||||
// | | g:::::::::ggg::::g | | |
|
||||
// | | g:::::::::::::::::g | | |
|
||||
// | | g::::::ggggg::::::gg | | |
|
||||
// | | g:::::g g:::::g | | |
|
||||
// offsetX -|-------->| g:::::g g:::::g | offsetY |
|
||||
// | | g:::::g g:::::g | | |
|
||||
// | | g::::::g g:::::g | | |
|
||||
// | | g:::::::ggggg:::::g | | |
|
||||
// | | g::::::::::::::::g | | height
|
||||
// | | gg::::::::::::::g | | |
|
||||
// baseline ---*---------|---- gggggggg::::::g-----*-------- |
|
||||
// / | | g:::::g | |
|
||||
// origin | | gggggg g:::::g | |
|
||||
// | | g:::::gg gg:::::g | |
|
||||
// | | g::::::ggg:::::::g | |
|
||||
// | | gg:::::::::::::g | |
|
||||
// | | ggg::::::ggg | |
|
||||
// | | gggggg | v
|
||||
// | +-------------------------+----------------- ymin
|
||||
// | |
|
||||
// |------------- advanceX ----------->|
|
||||
|
||||
/// A structure that describe a glyph.
|
||||
struct GlyphInfo
|
||||
{
|
||||
float Width; // Glyph's width in pixels.
|
||||
float Height; // Glyph's height in pixels.
|
||||
float OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
||||
float OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
||||
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
||||
};
|
||||
|
||||
// Font parameters and metrics.
|
||||
struct FontInfo
|
||||
{
|
||||
uint32_t PixelHeight; // Size this font was generated with.
|
||||
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
|
||||
float Descender; // The extents below the baseline in pixels (typically negative).
|
||||
float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
|
||||
float LineGap; // The spacing in pixels between one row's descent and the next row's ascent.
|
||||
float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font.
|
||||
};
|
||||
|
||||
// FreeType glyph rasterizer.
|
||||
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||
struct FreeTypeFont
|
||||
{
|
||||
bool Init(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
void Shutdown();
|
||||
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||
|
||||
bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap);
|
||||
void BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
|
||||
|
||||
// [Internals]
|
||||
FontInfo Info; // Font descriptor of the current font.
|
||||
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
||||
FT_Library FreetypeLibrary;
|
||||
FT_Face FreetypeFace;
|
||||
FT_Int32 FreetypeLoadFlags;
|
||||
};
|
||||
|
||||
// From SDL_ttf: Handy routines for converting from fixed point
|
||||
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
||||
|
||||
bool FreeTypeFont::Init(const ImFontConfig& cfg, unsigned int extra_user_flags)
|
||||
{
|
||||
// FIXME: substitute allocator
|
||||
FT_Error error = FT_Init_FreeType(&FreetypeLibrary);
|
||||
if (error != 0)
|
||||
return false;
|
||||
error = FT_New_Memory_Face(FreetypeLibrary, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &FreetypeFace);
|
||||
if (error != 0)
|
||||
return false;
|
||||
error = FT_Select_Charmap(FreetypeFace, FT_ENCODING_UNICODE);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
memset(&Info, 0, sizeof(Info));
|
||||
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||
|
||||
// Convert to freetype flags (nb: Bold and Oblique are processed separately)
|
||||
UserFlags = cfg.RasterizerFlags | extra_user_flags;
|
||||
FreetypeLoadFlags = FT_LOAD_NO_BITMAP;
|
||||
if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING;
|
||||
if (UserFlags & ImGuiFreeType::NoAutoHint) FreetypeLoadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||
if (UserFlags & ImGuiFreeType::ForceAutoHint) FreetypeLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
if (UserFlags & ImGuiFreeType::LightHinting)
|
||||
FreetypeLoadFlags |= FT_LOAD_TARGET_LIGHT;
|
||||
else if (UserFlags & ImGuiFreeType::MonoHinting)
|
||||
FreetypeLoadFlags |= FT_LOAD_TARGET_MONO;
|
||||
else
|
||||
FreetypeLoadFlags |= FT_LOAD_TARGET_NORMAL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeTypeFont::Shutdown()
|
||||
{
|
||||
if (FreetypeFace)
|
||||
{
|
||||
FT_Done_Face(FreetypeFace);
|
||||
FreetypeFace = NULL;
|
||||
FT_Done_FreeType(FreetypeLibrary);
|
||||
FreetypeLibrary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
||||
{
|
||||
// I'm not sure how to deal with font sizes properly.
|
||||
// As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph,
|
||||
// i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
||||
FT_Size_RequestRec req;
|
||||
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
req.width = 0;
|
||||
req.height = (uint32_t)pixel_height * 64;
|
||||
req.horiResolution = 0;
|
||||
req.vertResolution = 0;
|
||||
FT_Request_Size(FreetypeFace, &req);
|
||||
|
||||
// update font info
|
||||
FT_Size_Metrics metrics = FreetypeFace->size->metrics;
|
||||
Info.PixelHeight = (uint32_t)pixel_height;
|
||||
Info.Ascender = (float)FT_CEIL(metrics.ascender);
|
||||
Info.Descender = (float)FT_CEIL(metrics.descender);
|
||||
Info.LineSpacing = (float)FT_CEIL(metrics.height);
|
||||
Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender);
|
||||
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);
|
||||
}
|
||||
|
||||
bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo &glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap)
|
||||
{
|
||||
uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint);
|
||||
FT_Error error = FT_Load_Glyph(FreetypeFace, glyph_index, FreetypeLoadFlags);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
// Need an outline for this to work
|
||||
FT_GlyphSlot slot = FreetypeFace->glyph;
|
||||
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
|
||||
|
||||
if (UserFlags & ImGuiFreeType::Bold)
|
||||
FT_GlyphSlot_Embolden(slot);
|
||||
if (UserFlags & ImGuiFreeType::Oblique)
|
||||
FT_GlyphSlot_Oblique(slot);
|
||||
|
||||
// Retrieve the glyph
|
||||
error = FT_Get_Glyph(slot, &ft_glyph);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
// Rasterize
|
||||
error = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, NULL, true);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
ft_bitmap = (FT_BitmapGlyph)ft_glyph;
|
||||
glyph_info.AdvanceX = (float)FT_CEIL(slot->advance.x);
|
||||
glyph_info.OffsetX = (float)ft_bitmap->left;
|
||||
glyph_info.OffsetY = -(float)ft_bitmap->top;
|
||||
glyph_info.Width = (float)ft_bitmap->bitmap.width;
|
||||
glyph_info.Height = (float)ft_bitmap->bitmap.rows;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeTypeFont::BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
||||
{
|
||||
IM_ASSERT(ft_bitmap != NULL);
|
||||
|
||||
const uint32_t w = ft_bitmap->bitmap.width;
|
||||
const uint32_t h = ft_bitmap->bitmap.rows;
|
||||
const uint8_t* src = ft_bitmap->bitmap.buffer;
|
||||
const uint32_t src_pitch = ft_bitmap->bitmap.pitch;
|
||||
|
||||
if (multiply_table == NULL)
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
memcpy(dst, src, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
for (uint32_t x = 0; x < w; x++)
|
||||
dst[x] = multiply_table[src[x]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define STBRP_ASSERT(x) IM_ASSERT(x)
|
||||
#define STBRP_STATIC
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include "stb_rect_pack.h"
|
||||
|
||||
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported
|
||||
|
||||
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
||||
|
||||
atlas->TexID = NULL;
|
||||
atlas->TexWidth = atlas->TexHeight = 0;
|
||||
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||
atlas->ClearTexData();
|
||||
|
||||
ImVector<FreeTypeFont> fonts;
|
||||
fonts.resize(atlas->ConfigData.Size);
|
||||
|
||||
ImVec2 max_glyph_size(1.0f, 1.0f);
|
||||
|
||||
// Count glyphs/ranges, initialize font
|
||||
int total_glyphs_count = 0;
|
||||
int total_ranges_count = 0;
|
||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
||||
{
|
||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
||||
FreeTypeFont& font_face = fonts[input_i];
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
if (!font_face.Init(cfg, extra_flags))
|
||||
return false;
|
||||
|
||||
max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth);
|
||||
max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender);
|
||||
|
||||
if (!cfg.GlyphRanges)
|
||||
cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++)
|
||||
total_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
||||
}
|
||||
|
||||
// We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
|
||||
// Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||
atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
|
||||
|
||||
// We don't do the original first pass to determine texture height, but just rough estimate.
|
||||
// Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes.
|
||||
// Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the
|
||||
// shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.)
|
||||
const int total_rects = total_glyphs_count + atlas->CustomRects.size();
|
||||
float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f)));
|
||||
float min_rects_per_column = ceilf(total_rects / min_rects_per_row);
|
||||
atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f));
|
||||
|
||||
// Create texture
|
||||
atlas->TexHeight = ImUpperPowerOfTwo(atlas->TexHeight);
|
||||
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
||||
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
|
||||
|
||||
// Start packing
|
||||
ImVector<stbrp_node> pack_nodes;
|
||||
pack_nodes.resize(total_rects);
|
||||
stbrp_context context;
|
||||
stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects);
|
||||
|
||||
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||
ImFontAtlasBuildPackCustomRects(atlas, &context);
|
||||
|
||||
// Render characters, setup ImFont and glyphs for runtime
|
||||
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
||||
{
|
||||
ImFontConfig& cfg = atlas->ConfigData[input_i];
|
||||
FreeTypeFont& font_face = fonts[input_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
|
||||
const float ascent = font_face.Info.Ascender;
|
||||
const float descent = font_face.Info.Descender;
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float off_x = cfg.GlyphOffset.x;
|
||||
const float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
||||
|
||||
bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||
unsigned char multiply_table[256];
|
||||
if (multiply_enabled)
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
|
||||
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
|
||||
{
|
||||
for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint)
|
||||
{
|
||||
if (cfg.MergeMode && dst_font->FindGlyph((unsigned short)codepoint))
|
||||
continue;
|
||||
|
||||
FT_Glyph ft_glyph = NULL;
|
||||
FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph
|
||||
GlyphInfo glyph_info;
|
||||
if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap))
|
||||
continue;
|
||||
|
||||
// Pack rectangle
|
||||
stbrp_rect rect;
|
||||
rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering
|
||||
rect.h = (uint16_t)glyph_info.Height + 1;
|
||||
stbrp_pack_rects(&context, &rect, 1);
|
||||
|
||||
// Copy rasterized pixels to main texture
|
||||
uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x;
|
||||
font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL);
|
||||
FT_Done_Glyph(ft_glyph);
|
||||
|
||||
// Register glyph
|
||||
dst_font->AddGlyph((ImWchar)codepoint,
|
||||
glyph_info.OffsetX + off_x,
|
||||
glyph_info.OffsetY + off_y,
|
||||
glyph_info.OffsetX + off_x + glyph_info.Width,
|
||||
glyph_info.OffsetY + off_y + glyph_info.Height,
|
||||
rect.x / (float)atlas->TexWidth,
|
||||
rect.y / (float)atlas->TexHeight,
|
||||
(rect.x + glyph_info.Width) / (float)atlas->TexWidth,
|
||||
(rect.y + glyph_info.Height) / (float)atlas->TexHeight,
|
||||
glyph_info.AdvanceX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for (int n = 0; n < fonts.Size; n++)
|
||||
fonts[n].Shutdown();
|
||||
|
||||
ImFontAtlasBuildFinish(atlas);
|
||||
|
||||
return true;
|
||||
}
|
31
misc/freetype/imgui_freetype.h
Normal file
31
misc/freetype/imgui_freetype.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
|
||||
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||
// Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h" // IMGUI_API, ImFontAtlas
|
||||
|
||||
namespace ImGuiFreeType
|
||||
{
|
||||
// Hinting greatly impacts visuals (and glyph sizes).
|
||||
// When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output.
|
||||
// The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
|
||||
// The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
|
||||
|
||||
// You can set those flags on a per font basis in ImFontConfig::RasterizerFlags.
|
||||
// Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts.
|
||||
enum RasterizerFlags
|
||||
{
|
||||
// By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
|
||||
NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
|
||||
NoAutoHint = 1 << 1, // Disable auto-hinter.
|
||||
ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter.
|
||||
LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
|
||||
MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
|
||||
Bold = 1 << 5, // Styling: Should we artificially embolden the font?
|
||||
Oblique = 1 << 6 // Styling: Should we slant the font, emulating italic style?
|
||||
};
|
||||
|
||||
IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0);
|
||||
}
|
@ -33,8 +33,7 @@
|
||||
</Type>
|
||||
|
||||
<Type Name="ImGuiWindow">
|
||||
<DisplayString Condition="Active||WasActive">{{Name={Name,s}}}</DisplayString>
|
||||
<DisplayString Condition="!(Active||WasActive)">{{Name={Name,s}} Inactive}</DisplayString>
|
||||
<DisplayString>{{Name={Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d}}</DisplayString>
|
||||
</Type>
|
||||
|
||||
</AutoVisualizer>
|
Loading…
Reference in New Issue
Block a user