fix: Remaining Subpixel rendering issues

This commit is contained in:
WerWolv
2025-05-19 00:00:32 +02:00
parent b6387c3f64
commit 0f0bff1685
4 changed files with 54 additions and 64 deletions

View File

@@ -423,10 +423,10 @@ void ImGui_ImplOpenGL3_NewFrame()
bool useFontShaders = false;
void FontShadersOn(const ImDrawList *parent_list, const ImDrawCmd *cmd) {
useFontShaders = !useFontShaders;
useFontShaders = true;
}
void FontShadersOff(const ImDrawList *parent_list, const ImDrawCmd *cmd) {
useFontShaders = !useFontShaders;
useFontShaders = false;
}
ImDrawCallback ImGui_ImplOpenGL3_TurnFontShadersOn = &FontShadersOn;
ImDrawCallback ImGui_ImplOpenGL3_TurnFontShadersOff = &FontShadersOff;

View File

@@ -1716,6 +1716,15 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32
font_size = _Data->FontSize;
IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
ImVec4 clip_rect = _CmdHeader.ClipRect;
if (cpu_fine_clip_rect)
{
clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
}
// IMHEX PATCH BEGIN
int flags;
bool is_subpixel = false;
@@ -1726,15 +1735,9 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32
if (is_subpixel)
AddCallback(ImGui_ImplOpenGL3_TurnFontShadersOn, NULL);
// IMHEX PATCH END
ImVec4 clip_rect = _CmdHeader.ClipRect;
if (cpu_fine_clip_rect)
{
clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
}
font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
// IMHEX PATCH BEGIN
if (is_subpixel)
AddCallback(ImGui_ImplOpenGL3_TurnFontShadersOff, NULL);
@@ -3329,15 +3332,8 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid
TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
// IMHEX PATCH BEGIN
if (FontBuilderFlags & ImGuiFreeTypeBuilderFlags_SubPixel) {
for (int n = TexWidth * TexHeight; n > 0; n--,src++)
*dst++ = IM_COL32(*src, *src, *src, *src);
} else {
for (int n = TexWidth * TexHeight; n > 0; n--)
*dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
}
// IMHEX PATCH END
for (int n = TexWidth * TexHeight; n > 0; n--)
*dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
}
}

View File

@@ -29,7 +29,6 @@ namespace hex::fonts {
}
float calculateFontDescend(FT_Library ft, float fontSize) const {
if (ft == nullptr) {
log::fatal("FreeType not initialized");
return 0.0f;
@@ -46,14 +45,17 @@ namespace hex::fonts {
if (m_font->FontSize > 0.0F)
size = m_font->FontSize * std::max(1.0F, std::floor(ImHexApi::System::getGlobalScale()));
else
size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize;
size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize * std::floor(ImHexApi::System::getGlobalScale());
if (FT_Set_Pixel_Sizes(face, size, size) != 0) {
log::fatal("Failed to set pixel size");
return 0.0f;
}
FT_Size_RequestRec req;
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
req.width = 0;
req.height = (uint32_t)(IM_ROUND(size) * 64.0F);
req.horiResolution = 0;
req.vertResolution = 0;
FT_Request_Size(face, &req);
return face->size->metrics.descender / 64.0F;
return face->size->metrics.ascender / 64.0F;
}
ImFont* getFont() { return m_font; }
@@ -249,18 +251,13 @@ namespace hex::fonts {
log::fatal("Failed to load face");
return 0.0f;
}
// Calculate the expected font size
auto size = fontSize;
if (font.defaultSize.has_value())
size = font.defaultSize.value() * std::max(1.0F, std::floor(ImHexApi::System::getGlobalScale()));
else
size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize;
if (FT_Set_Pixel_Sizes(face, size, size) != 0) {
log::fatal("Failed to set pixel size");
return false;
}
FT_Size_RequestRec req;
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
req.width = 0;
req.height = (uint32_t)(IM_ROUND(fontSize) * 64.0F);
req.horiResolution = 0;
req.vertResolution = 0;
FT_Request_Size(face, &req);
return face->size->metrics.descender / 64.0F;
}

View File

@@ -22,7 +22,7 @@
namespace hex::fonts {
bool BuildSubPixelAtlas(FontAtlas *fontAtlas, float fontSize) {
bool BuildSubPixelAtlas(FontAtlas *fontAtlas) {
FT_Library ft = nullptr;
if (FT_Init_FreeType(&ft) != 0) {
log::fatal("Failed to initialize FreeType");
@@ -41,10 +41,10 @@ namespace hex::fonts {
std::map<ImS32, ft::Bitmap> bitmapLCD;
ImU32 fontCount = io.Fonts->ConfigData.Size;
for (ImU32 i = 0; i < fontCount; i++) {
std::string fontName = io.Fonts->ConfigData[i].Name;
const auto config = io.Fonts->ConfigData[i];
const auto &fontName = config.Name;
std::ranges::transform(fontName.begin(), fontName.end(), fontName.begin(), [](unsigned char c) { return std::tolower(c); });
if (fontName == "nonscalable") {
if (hex::equalsIgnoreCase(fontName, "nonscalable")) {
continue;
}
@@ -53,25 +53,20 @@ namespace hex::fonts {
return false;
}
float actualFontSize;
if (fontName.find("icon") != std::string::npos)
actualFontSize = ImHexApi::Fonts::pointsToPixels(fontSize);
else
actualFontSize = fontSize;
if (FT_Set_Pixel_Sizes(face, actualFontSize, actualFontSize) != 0) {
log::fatal("Failed to set pixel size");
return false;
}
FT_Size_RequestRec req;
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
req.width = 0;
req.height = (uint32_t)(IM_ROUND(config.SizePixels) * 64.0F);
req.horiResolution = 0;
req.vertResolution = 0;
FT_Request_Size(face, &req);
FT_UInt gIndex;
FT_ULong charCode = FT_Get_First_Char(face, &gIndex);
while (gIndex != 0) {
FT_UInt glyph_index = FT_Get_Char_Index(face, charCode);
if (FT_Load_Glyph(face, glyph_index, FT_LOAD_TARGET_LCD | FT_LOAD_TARGET_LIGHT | FT_LOAD_RENDER) != 0) {
if (FT_Load_Glyph(face, glyph_index, FT_LOAD_TARGET_LCD | FT_LOAD_TARGET_LIGHT | FT_LOAD_RENDER) != 0) {
IM_ASSERT(true && "Failed to load glyph");
return false;
}
@@ -82,17 +77,15 @@ namespace hex::fonts {
continue;
}
auto width = bitmap_lcd.getWidth() / 3;
auto width = bitmap_lcd.getWidth() / 3.0F;
auto height = bitmap_lcd.getHeight();
FT_GlyphSlot slot = face->glyph;
FT_Size size = face->size;
ImVec2 offset = ImVec2((slot->metrics.horiBearingX / 64.0f), (size->metrics.ascender - slot->metrics.horiBearingY) / 64.0f);
if (fontName.find("codicon") != std::string::npos)
offset.x -= 1.0f;
ImS32 advance = (float) slot->advance.x / 64.0f;
if (offset.x+width > advance && advance >= (int) width)
offset.x = advance - width;
ImVec2 offset = ImVec2(face->glyph->bitmap_left, -face->glyph->bitmap_top);
offset.x += config.GlyphOffset.x;
offset.y += size->metrics.ascender / 64.0F;
ImS32 advance = (float) slot->advance.x / 64.0F;
ImS32 rect_id = io.Fonts->AddCustomRectFontGlyph(io.Fonts->Fonts[0], charCode, width, height, advance, offset);
rect_ids.push_back(rect_id);
@@ -154,6 +147,7 @@ namespace hex::fonts {
u32 fontIndex = 0;
auto io = ImGui::GetIO();
io.Fonts = fontAtlas->getAtlas();
// Check if Unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows
// The Mesa3D software renderer on Windows identifies itself as "VMware, Inc."
bool shouldLoadUnicode = ContentRegistry::Settings::read<bool>("hex.fonts.setting.font", "hex.fonts.setting.font.load_all_unicode_chars", false) && ImHexApi::System::getGPUVendor() != "VMware, Inc.";
@@ -221,13 +215,16 @@ namespace hex::fonts {
glyphRanges.push_back(glyphRange);
// Calculate the glyph offset for the font
const ImVec2 offset = { font.offset.x, font.offset.y - (defaultFont->calculateFontDescend(ft, realFontSize) - fontAtlas->calculateFontDescend(ft, font, realFontSize)) };
// Load the font
float size = realFontSize;
if (font.defaultSize.has_value())
size = font.defaultSize.value() * ImHexApi::System::getBackingScaleFactor();
const ImVec2 offset = { font.offset.x, font.offset.y + ImCeil(4_scaled) };
fontAtlas->addFontFromMemory(font.fontData, size, !font.defaultSize.has_value(), offset, glyphRanges.back());
if (!font.scalable.value_or(true)) {
std::string fontName = "NonScalable";
auto nameSize = fontName.size();
@@ -252,6 +249,6 @@ namespace hex::fonts {
}
return true;
} else
return BuildSubPixelAtlas(fontAtlas,fontSize);
return BuildSubPixelAtlas(fontAtlas);
}
}