diff --git a/Data/Sys/Resources/VeraMono.ttf b/Data/Sys/Resources/VeraMono.ttf new file mode 100644 index 0000000000..139f0b4311 Binary files /dev/null and b/Data/Sys/Resources/VeraMono.ttf differ diff --git a/Data/Sys/Resources/VeraMono_Copyright.txt b/Data/Sys/Resources/VeraMono_Copyright.txt new file mode 100644 index 0000000000..e651be1c4f --- /dev/null +++ b/Data/Sys/Resources/VeraMono_Copyright.txt @@ -0,0 +1,124 @@ +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not *sold* by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. + diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 0b6a2fd6c1..de61b5b473 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -422,6 +422,7 @@ const Info MAIN_USE_BUILT_IN_TITLE_DATABASE{ {System::Main, "Interface", "UseBuiltinTitleDatabase"}, true}; const Info MAIN_THEME_NAME{{System::Main, "Interface", "ThemeName"}, DEFAULT_THEME_DIR}; +const Info MAIN_IMGUI_FONT_SIZE{{System::Main, "Interface", "ImguiFontSize"}, 16}; const Info MAIN_PAUSE_ON_FOCUS_LOST{{System::Main, "Interface", "PauseOnFocusLost"}, false}; const Info MAIN_ENABLE_DEBUGGING{{System::Main, "Interface", "DebugModeEnabled"}, false}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 774824e450..df4e6029be 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -255,6 +255,7 @@ extern const Info MAIN_INTERFACE_LANGUAGE; extern const Info MAIN_SHOW_ACTIVE_TITLE; extern const Info MAIN_USE_BUILT_IN_TITLE_DATABASE; extern const Info MAIN_THEME_NAME; +extern const Info MAIN_IMGUI_FONT_SIZE; extern const Info MAIN_PAUSE_ON_FOCUS_LOST; extern const Info MAIN_ENABLE_DEBUGGING; diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.cpp b/Source/Core/DolphinQt/Settings/InterfacePane.cpp index 71a044d658..87fe7f9d32 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.cpp +++ b/Source/Core/DolphinQt/Settings/InterfacePane.cpp @@ -28,6 +28,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" +#include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" @@ -151,6 +152,20 @@ void InterfacePane::CreateUI() m_combobox_userstyle->addItem(tr("(System)"), static_cast(Settings::StyleType::System)); + // ImGui Font Size + auto* imgui_size_layout = new QHBoxLayout(); + + m_imgui_size = new ConfigSlider(12, 40, Config::MAIN_IMGUI_FONT_SIZE); + auto* imgui_size_number = new QLabel(QString::number(m_imgui_size->value())); + connect(m_imgui_size, &QSlider::valueChanged, this, [this, imgui_size_number](int value) { + imgui_size_number->setText(QString::number(value)); + }); + + imgui_size_layout->addWidget(m_imgui_size); + imgui_size_layout->addWidget(imgui_size_number); + imgui_size_layout->setContentsMargins(0, 0, 0, 0); + combobox_layout->addRow(tr("Imgui Font Size:"), imgui_size_layout); + // TODO: Support forcing light/dark on other OSes too. #ifdef _WIN32 m_combobox_userstyle->addItem(tr("(Light)"), static_cast(Settings::StyleType::Light)); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.h b/Source/Core/DolphinQt/Settings/InterfacePane.h index ffe1efa087..49aa30395d 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.h +++ b/Source/Core/DolphinQt/Settings/InterfacePane.h @@ -7,6 +7,7 @@ class ConfigBool; class ConfigRadioInt; +class ConfigSlider; class ConfigStringChoice; class QLabel; class QVBoxLayout; @@ -43,6 +44,7 @@ private: ConfigStringChoice* m_combobox_theme; ToolTipComboBox* m_combobox_userstyle; QLabel* m_label_userstyle; + ConfigSlider* m_imgui_size; ConfigBool* m_checkbox_top_window; ConfigBool* m_checkbox_use_builtin_title_database; ToolTipCheckBox* m_checkbox_show_debugging_ui; diff --git a/Source/Core/VideoCommon/OnScreenUI.cpp b/Source/Core/VideoCommon/OnScreenUI.cpp index d1c15f7f80..f35995c1c1 100644 --- a/Source/Core/VideoCommon/OnScreenUI.cpp +++ b/Source/Core/VideoCommon/OnScreenUI.cpp @@ -3,7 +3,9 @@ #include "VideoCommon/OnScreenUI.h" +#include "Common/CommonPaths.h" #include "Common/EnumMap.h" +#include "Common/FileUtil.h" #include "Common/Profiler.h" #include "Common/Timer.h" @@ -57,6 +59,7 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale) // Don't create an ini file. TODO: Do we want this in the future? ImGui::GetIO().IniFilename = nullptr; + SetFont(); SetScale(scale); PortableVertexDeclaration vdecl = {}; @@ -71,31 +74,6 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale) return false; } - // Font texture(s). - { - ImGuiIO& io = ImGui::GetIO(); - u8* font_tex_pixels; - int font_tex_width, font_tex_height; - io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); - - TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, - AbstractTextureFormat::RGBA8, 0, - AbstractTextureType::Texture_2DArray); - std::unique_ptr font_tex = - g_gfx->CreateTexture(font_tex_config, "ImGui font texture"); - if (!font_tex) - { - PanicAlertFmt("Failed to create ImGui texture"); - return false; - } - font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, - sizeof(u32) * font_tex_width * font_tex_height); - - io.Fonts->TexID = *font_tex.get(); - - m_imgui_textures.push_back(std::move(font_tex)); - } - if (!RecompileImGuiPipeline()) return false; @@ -183,6 +161,9 @@ bool OnScreenUI::RecompileImGuiPipeline() void OnScreenUI::BeginImGuiFrame(u32 width, u32 height) { + // Check for font changes + if (Config::Get(Config::MAIN_IMGUI_FONT_SIZE) != m_custom_font_size) + SetFont(); std::unique_lock imgui_lock(m_imgui_mutex); BeginImGuiFrameUnlocked(width, height); } @@ -279,11 +260,12 @@ void OnScreenUI::DrawDebugText() { // Position under the FPS display. ImGui::SetNextWindowPos( - ImVec2(ImGui::GetIO().DisplaySize.x - 10.f * m_backbuffer_scale, 80.f * m_backbuffer_scale), + ImVec2(ImGui::GetIO().DisplaySize.x - ImGui::GetFontSize() * m_backbuffer_scale, + 80.f * m_backbuffer_scale), ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSizeConstraints( - ImVec2(150.0f * m_backbuffer_scale, 20.0f * m_backbuffer_scale), - ImGui::GetIO().DisplaySize); + ImGui::SetNextWindowSizeConstraints(ImVec2(5.0f * ImGui::GetFontSize() * m_backbuffer_scale, + 2.1f * ImGui::GetFontSize() * m_backbuffer_scale), + ImGui::GetIO().DisplaySize); if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing)) { auto& movie = Core::System::GetInstance().GetMovie(); @@ -417,6 +399,53 @@ std::unique_lock OnScreenUI::GetImGuiLock() return std::unique_lock(m_imgui_mutex); } +void OnScreenUI::SetFont() +{ + ImGuiIO& io = ImGui::GetIO(); + + // If imgui has already been loaded and is running. + if (ImGui::GetFrameCount() != 0) + io.Fonts->Clear(); + + m_custom_font_size = Config::Get(Config::MAIN_IMGUI_FONT_SIZE); + const std::string file = + File::GetSysDirectory() + DIR_SEP + RESOURCES_DIR + DIR_SEP + "VeraMono.ttf"; + + if (File::Exists(file)) + { + // Small font for things like graph labels. Called with FONTS[0]. + io.Fonts->AddFontFromFileTTF(file.c_str(), 14.0f); + auto* user_font = io.Fonts->AddFontFromFileTTF(file.c_str(), m_custom_font_size); + + io.Fonts->Build(); + io.FontDefault = user_font; + } + + // This always runs once on loading a game. Only runs again if changing fonts. + m_imgui_textures.clear(); + + u8* font_tex_pixels; + int font_tex_width, font_tex_height; + io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height); + + TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1, + AbstractTextureFormat::RGBA8, 0, + AbstractTextureType::Texture_2DArray); + std::unique_ptr font_tex = + g_gfx->CreateTexture(font_tex_config, "ImGui font texture"); + if (!font_tex) + { + PanicAlertFmt("Failed to create ImGui texture"); + return; + } + font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels, + sizeof(u32) * font_tex_width * font_tex_height); + + io.Fonts->TexID = *font_tex.get(); + + m_imgui_textures.push_back(std::move(font_tex)); +} + void OnScreenUI::SetScale(float backbuffer_scale) { ImGui::GetIO().DisplayFramebufferScale.x = backbuffer_scale; diff --git a/Source/Core/VideoCommon/OnScreenUI.h b/Source/Core/VideoCommon/OnScreenUI.h index 28749807be..10ff1cb717 100644 --- a/Source/Core/VideoCommon/OnScreenUI.h +++ b/Source/Core/VideoCommon/OnScreenUI.h @@ -49,6 +49,7 @@ public: // Recompiles ImGui pipeline - call when stereo mode changes. bool RecompileImGuiPipeline(); + void SetFont(); void SetScale(float backbuffer_scale); void Finalize(); @@ -79,6 +80,7 @@ private: std::map, std::less<>> m_challenge_texture_map; #endif // USE_RETRO_ACHIEVEMENTS + int m_custom_font_size; bool m_ready = false; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/PerformanceMetrics.cpp b/Source/Core/VideoCommon/PerformanceMetrics.cpp index 520f9d8b95..8ec18a5117 100644 --- a/Source/Core/VideoCommon/PerformanceMetrics.cpp +++ b/Source/Core/VideoCommon/PerformanceMetrics.cpp @@ -127,7 +127,6 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) } const float window_padding = 8.f * backbuffer_scale; - const float window_width = 93.f * backbuffer_scale; const ImVec2& display_size = ImGui::GetIO().DisplaySize; const bool display_size_changed = @@ -161,9 +160,8 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) ImGui::SetWindowPos(ImVec2(clamped_window_x, clamped_window_y), ImGuiCond_Always); }; - const float graph_width = 50.f * backbuffer_scale + 3.f * window_width + 2.f * window_padding; - const float graph_height = - std::min(200.f * backbuffer_scale, display_size.y - 85.f * backbuffer_scale); + const float graph_width = display_size.x / 4.0; + const float graph_height = display_size.y / 4.0; const bool stack_vertically = !g_ActiveConfig.bShowGraphs; @@ -171,17 +169,20 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 14.f * backbuffer_scale); if (g_ActiveConfig.bShowGraphs) { + // Force smaller font + ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]); + ImGui::PushStyleColor(ImGuiCol_ResizeGrip, 0); + const auto graph_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | movable_flag | + ImGuiWindowFlags_NoFocusOnAppearing; ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 4.f * backbuffer_scale)); // Position in the top-right corner of the screen. - ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(graph_width, graph_height)); + ImGui::SetNextWindowSize(ImVec2(graph_width, graph_height), ImGuiCond_FirstUseEver); ImGui::SetNextWindowBgAlpha(bg_alpha); - window_y += graph_height + window_padding; - - if (ImGui::Begin("PerformanceGraphs", nullptr, imgui_flags)) + if (ImGui::Begin("PerformanceGraphs", nullptr, graph_flags)) { static constexpr std::size_t num_ticks = 17; static constexpr std::array tick_marks = {0.0, @@ -203,6 +204,7 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) 2000.0}; clamp_window_position(); + window_y += ImGui::GetWindowHeight(); const DT vblank_time = m_vps_counter.GetDtAvg() + 2 * m_vps_counter.GetDtStd(); const DT frame_time = m_fps_counter.GetDtAvg() + 2 * m_fps_counter.GetDtStd(); @@ -245,25 +247,23 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) ImGui::PopStyleVar(); } ImGui::End(); + ImGui::PopFont(); + ImGui::PopStyleColor(); } if (g_ActiveConfig.bShowSpeed) { // Position in the top-right corner of the screen. - float window_height = 47.f * backbuffer_scale; - ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); ImGui::SetNextWindowBgAlpha(bg_alpha); - if (stack_vertically) - window_y += window_height + window_padding; - else - window_x -= window_width + window_padding; - if (ImGui::Begin("SpeedStats", nullptr, imgui_flags)) { + if (stack_vertically) + window_y += ImGui::GetWindowHeight() + window_padding; + else + window_x -= ImGui::GetWindowWidth() + window_padding; clamp_window_position(); ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Speed:%4.0lf%%", 100.0 * speed); ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Max:%6.0lf%%", 100.0 * GetMaxSpeed()); @@ -273,22 +273,17 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) if (g_ActiveConfig.bShowFPS || g_ActiveConfig.bShowFTimes) { - int count = g_ActiveConfig.bShowFPS + 2 * g_ActiveConfig.bShowFTimes; - float window_height = (12.f + 17.f * count) * backbuffer_scale; - // Position in the top-right corner of the screen. ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); ImGui::SetNextWindowBgAlpha(bg_alpha); - if (stack_vertically) - window_y += window_height + window_padding; - else - window_x -= window_width + window_padding; - if (ImGui::Begin("FPSStats", nullptr, imgui_flags)) { + if (stack_vertically) + window_y += ImGui::GetWindowHeight() + window_padding; + else + window_x -= ImGui::GetWindowWidth() + window_padding; clamp_window_position(); if (g_ActiveConfig.bShowFPS) ImGui::TextColored(ImVec4(r, g, b, 1.0f), "FPS:%7.2lf", fps); @@ -305,22 +300,17 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale) if (g_ActiveConfig.bShowVPS || g_ActiveConfig.bShowVTimes) { - int count = g_ActiveConfig.bShowVPS + 2 * g_ActiveConfig.bShowVTimes; - float window_height = (12.f + 17.f * count) * backbuffer_scale; - // Position in the top-right corner of the screen. ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition, ImVec2(1.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(window_width, (12.f + 17.f * count) * backbuffer_scale)); ImGui::SetNextWindowBgAlpha(bg_alpha); - if (stack_vertically) - window_y += window_height + window_padding; - else - window_x -= window_width + window_padding; - if (ImGui::Begin("VPSStats", nullptr, imgui_flags)) { + if (stack_vertically) + window_y += ImGui::GetWindowHeight() + window_padding; + else + window_x -= ImGui::GetWindowWidth() + window_padding; clamp_window_position(); if (g_ActiveConfig.bShowVPS) ImGui::TextColored(ImVec4(r, g, b, 1.0f), "VPS:%7.2lf", vps);