mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-09 23:54:20 +00:00
Merge 08fa252c96 into f5384544cb
This commit is contained in:
commit
d93204adb8
1 changed files with 155 additions and 22 deletions
|
|
@ -108,7 +108,7 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_
|
|||
//-------------------------------------------------------------------------
|
||||
|
||||
#define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point
|
||||
#define FT_SCALEFACTOR 64.0f
|
||||
#define FT_SCALEFACTOR 64.0f // For converting from/to 26.6 factionals
|
||||
|
||||
// Glyph metrics:
|
||||
// --------------
|
||||
|
|
@ -432,19 +432,59 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s
|
|||
|
||||
FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize);
|
||||
FT_Activate_Size(bd_baked_data->FtSize);
|
||||
|
||||
// Vuhdo 2017: "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_Set_Pixel_Sizes() doesn't seem to get us the same result."
|
||||
// (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL)
|
||||
const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity;
|
||||
FT_Size_RequestRec req;
|
||||
req.type = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
req.width = 0;
|
||||
req.height = (uint32_t)(size * 64 * rasterizer_density);
|
||||
req.horiResolution = 0;
|
||||
req.vertResolution = 0;
|
||||
FT_Request_Size(bd_font_data->FtFace, &req);
|
||||
if (((bd_font_data->FtFace->face_flags & FT_FACE_FLAG_FIXED_SIZES) != 0) && ((bd_font_data->FtFace->face_flags & FT_FACE_FLAG_SCALABLE) == 0) && ((bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) != 0))
|
||||
{
|
||||
IM_ASSERT(bd_font_data->FtFace->num_fixed_sizes > 0);
|
||||
|
||||
// Loop over sizes and pick the closest, larger (or better equal) size.
|
||||
int best_index = 0;
|
||||
float best_height = bd_font_data->FtFace->available_sizes[best_index].y_ppem / FT_SCALEFACTOR;
|
||||
for (int i = 1; i < bd_font_data->FtFace->num_fixed_sizes; i++)
|
||||
{
|
||||
const float cur_height = bd_font_data->FtFace->available_sizes[i].y_ppem / FT_SCALEFACTOR;
|
||||
// TODO: is this overkill?
|
||||
// TODO: is-float-close with epsilon param would be nice, maybe
|
||||
if (ImFabs(cur_height - size) < 0.001f)
|
||||
{
|
||||
best_index = i;
|
||||
best_height = cur_height;
|
||||
break;
|
||||
}
|
||||
else if (cur_height < size)
|
||||
{
|
||||
if (best_height < cur_height)
|
||||
{
|
||||
best_index = i;
|
||||
best_height = cur_height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (best_height < size && best_height < cur_height)
|
||||
{
|
||||
best_index = i;
|
||||
best_height = cur_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
FT_Select_Size(bd_font_data->FtFace, best_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vuhdo 2017: "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_Set_Pixel_Sizes() doesn't seem to get us the same result."
|
||||
// (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL)
|
||||
|
||||
FT_Size_RequestRec req;
|
||||
req.type = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
req.width = 0;
|
||||
req.height = (uint32_t)(size * FT_SCALEFACTOR * rasterizer_density);
|
||||
req.horiResolution = 0;
|
||||
req.vertResolution = 0;
|
||||
FT_Request_Size(bd_font_data->FtFace, &req);
|
||||
}
|
||||
|
||||
// Output
|
||||
if (src->MergeMode == false)
|
||||
|
|
@ -472,6 +512,71 @@ static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig
|
|||
bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE()
|
||||
}
|
||||
|
||||
static void RescaleBitmap(uint32_t* dst, const int dst_w, const int dst_h, uint32_t* src, const int src_w, const int src_h)
|
||||
{
|
||||
#if 0
|
||||
// Point Sampling / Nearest Neighbor
|
||||
for (int y = 0; y < dst_h; y++)
|
||||
{
|
||||
const int src_y = ImFloor(((y + 0.5f) * src_h) / dst_h);
|
||||
for (int x = 0; x < dst_w; x++)
|
||||
{
|
||||
const int src_x = ImFloor(((x + 0.5f) * src_w) / dst_w);
|
||||
dst[y * dst_w + x] = src[src_y * src_w + src_x];
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Box sampling - Imagine projecting the new, smaller pixels onto the larger source, covering multiple pixel.
|
||||
for (int y = 0; y < dst_h; y++)
|
||||
{
|
||||
for (int x = 0; x < dst_w; x++)
|
||||
{
|
||||
// We perform a weighted mean.
|
||||
ImVec4 color;
|
||||
float weight_sum = 0.f;
|
||||
|
||||
// Walk from upper edge to bottom edge (vertical)
|
||||
const float edge_up = ((float)y * src_h) / dst_h;
|
||||
const float edge_down = ((y + 1.f) * src_h) / dst_h;
|
||||
for (float frac_pos_y = edge_up; frac_pos_y < edge_down;)
|
||||
{
|
||||
const int src_y = (int)ImFloor(frac_pos_y); IM_ASSERT(src_y < src_h);
|
||||
const float frac_y = 1.f - (frac_pos_y - src_y);
|
||||
|
||||
// Walk from left edge to right edge (horizontal)
|
||||
const float edge_left = ((float)x * src_w) / dst_w;
|
||||
const float edge_right = ((x + 1.f) * src_w) / dst_w;
|
||||
for (float frac_pos_x = edge_left; frac_pos_x < edge_right;)
|
||||
{
|
||||
const int src_x = (int)ImFloor(frac_pos_x); IM_ASSERT(src_x < src_w);
|
||||
const float frac_x = 1.f - (frac_pos_x - src_x);
|
||||
|
||||
const float src_pixel_weight = frac_x * frac_y;
|
||||
|
||||
const ImVec4 pixel_color = ImGui::ColorConvertU32ToFloat4(src[src_y * src_w + src_x]);
|
||||
color.x += pixel_color.x * src_pixel_weight;
|
||||
color.y += pixel_color.y * src_pixel_weight;
|
||||
color.z += pixel_color.z * src_pixel_weight;
|
||||
color.w += pixel_color.w * src_pixel_weight;
|
||||
weight_sum += src_pixel_weight;
|
||||
|
||||
frac_pos_x += frac_x;
|
||||
}
|
||||
|
||||
frac_pos_y += frac_y;
|
||||
}
|
||||
|
||||
color.x /= weight_sum;
|
||||
color.y /= weight_sum;
|
||||
color.z /= weight_sum;
|
||||
color.w /= weight_sum;
|
||||
|
||||
dst[y * dst_w + x] = ImGui::ColorConvertFloat4ToU32(color);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x)
|
||||
{
|
||||
ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
|
||||
|
|
@ -494,9 +599,21 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
|
|||
FT_Face face = bd_font_data->FtFace;
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity;
|
||||
float bitmap_x_scale = 1.f;
|
||||
float bitmap_y_scale = 1.f;
|
||||
if (((face->face_flags & FT_FACE_FLAG_FIXED_SIZES) != 0) && ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) && ((bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) != 0))
|
||||
{
|
||||
// TODO: what if this just means invisible?
|
||||
IM_ASSERT(bd_font_data->FtFace->size->metrics.x_ppem > 0);
|
||||
IM_ASSERT(bd_font_data->FtFace->size->metrics.y_ppem > 0);
|
||||
|
||||
// Scale fixed size bitmap to target size
|
||||
bitmap_x_scale = baked->Size / bd_font_data->FtFace->size->metrics.x_ppem;
|
||||
bitmap_y_scale = baked->Size / bd_font_data->FtFace->size->metrics.y_ppem;
|
||||
}
|
||||
|
||||
// Load metrics only mode
|
||||
const float advance_x = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density;
|
||||
const float advance_x = ((slot->advance.x / FT_SCALEFACTOR) * bitmap_x_scale) / rasterizer_density;
|
||||
if (out_advance_x != NULL)
|
||||
{
|
||||
IM_ASSERT(out_glyph == NULL);
|
||||
|
|
@ -511,9 +628,9 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
|
|||
if (error != 0 || ft_bitmap == nullptr)
|
||||
return false;
|
||||
|
||||
const int w = (int)ft_bitmap->width;
|
||||
const int h = (int)ft_bitmap->rows;
|
||||
const bool is_visible = (w != 0 && h != 0);
|
||||
const int bitmap_w = (int)ft_bitmap->width;
|
||||
const int bitmap_h = (int)ft_bitmap->rows;
|
||||
const bool is_visible = (bitmap_w != 0 && bitmap_h != 0);
|
||||
|
||||
// Prepare glyph
|
||||
out_glyph->Codepoint = codepoint;
|
||||
|
|
@ -522,6 +639,10 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
|
|||
// Pack and retrieve position inside texture atlas
|
||||
if (is_visible)
|
||||
{
|
||||
const int w = (int)ImCeil(bitmap_w * bitmap_x_scale);
|
||||
const int h = (int)ImCeil(bitmap_h * bitmap_y_scale);
|
||||
const bool rescaling = h != bitmap_h || w != bitmap_w;
|
||||
|
||||
ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
|
||||
if (pack_id == ImFontAtlasRectId_Invalid)
|
||||
{
|
||||
|
|
@ -531,10 +652,22 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
|
|||
}
|
||||
ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
|
||||
|
||||
// Render pixels to our temporary buffer
|
||||
atlas->Builder->TempBuffer.resize(w * h * 4);
|
||||
// Render pixels to our temporary buffer, while making sure we have space for an extra copy used during rescaling.
|
||||
atlas->Builder->TempBuffer.resize(((rescaling ? bitmap_w * bitmap_h : 0) + w * h) * 4);
|
||||
uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data;
|
||||
ImGui_ImplFreeType_BlitGlyph(ft_bitmap, temp_buffer, w);
|
||||
// Blit (and convert) into the first bitmap_w * bitmap_h * 4 bytes.
|
||||
ImGui_ImplFreeType_BlitGlyph(ft_bitmap, temp_buffer, bitmap_w);
|
||||
|
||||
if (rescaling)
|
||||
{
|
||||
uint32_t* dst_buffer = temp_buffer + bitmap_w * bitmap_h;
|
||||
|
||||
// Perform rescale, from temp_buffer (bitmap_w * bitmap_h) to dst_buffer (w * h)
|
||||
RescaleBitmap(dst_buffer, w, h, temp_buffer, bitmap_w, bitmap_h);
|
||||
|
||||
// Redirect to rescaled part of the buffer
|
||||
temp_buffer = dst_buffer;
|
||||
}
|
||||
|
||||
const float ref_size = baked->OwnerFont->Sources[0]->SizePixels;
|
||||
const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
|
||||
|
|
@ -544,8 +677,8 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
|
|||
float recip_v = 1.0f / rasterizer_density;
|
||||
|
||||
// Register glyph
|
||||
float glyph_off_x = (float)face->glyph->bitmap_left;
|
||||
float glyph_off_y = (float)-face->glyph->bitmap_top;
|
||||
float glyph_off_x = ImCeil((float)face->glyph->bitmap_left * bitmap_x_scale);
|
||||
float glyph_off_y = ImCeil((float)-face->glyph->bitmap_top * bitmap_y_scale);
|
||||
out_glyph->X0 = glyph_off_x * recip_h + font_off_x;
|
||||
out_glyph->Y0 = glyph_off_y * recip_v + font_off_y;
|
||||
out_glyph->X1 = (glyph_off_x + w) * recip_h + font_off_x;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue