SDL3_ttf work

This commit is contained in:
Henrik Rydgård
2026-05-15 13:35:21 +02:00
parent f2ac4a65be
commit 2b821037d7
4 changed files with 61 additions and 48 deletions
+8 -2
View File
@@ -326,17 +326,21 @@ if(USING_EGL)
endif()
set(SDL_LIB_TARGET "")
set(SDL_TTF_LIB_TARGET "")
if(NOT LIBRETRO AND NOT IOS AND NOT MACOSX)
find_package(SDL3 REQUIRED)
set(SDL_LIB_TARGET SDL3::SDL3)
find_package(SDL3_ttf REQUIRED)
set(SDL_TTF_LIB_TARGET SDL3_ttf::SDL3_ttf)
add_compile_definitions(USE_SDL3_TTF)
message(STATUS "Using SDL3")
endif()
if(MACOSX AND NOT IOS)
if(USE_SYSTEM_LIBSDL2)
find_package(SDL2)
find_package(SDL2_ttf)
find_package(SDL3_ttf QUIET)
else()
find_library(SDL2Fwk SDL2 REQUIRED PATHS SDL/macOS)
message(STATUS "found SDL2Fwk=${SDL2Fwk}")
@@ -1521,7 +1525,9 @@ else()
SDL/SDLVulkanGraphicsContext.cpp
)
endif()
# SDL2_ttf integration is disabled while migrating to SDL3-only.
if(SDL_TTF_LIB_TARGET)
list(APPEND nativeExtraLibs ${SDL_TTF_LIB_TARGET})
endif()
if(APPLE)
list(APPEND nativeExtra
SDL/SDLJoystick.h
+1 -1
View File
@@ -316,7 +316,7 @@ TextDrawer *TextDrawer::Create(Draw::DrawContext *draw) {
drawer = new TextDrawerQt(draw);
#elif PPSSPP_PLATFORM(ANDROID)
drawer = new TextDrawerAndroid(draw);
#elif USE_SDL2_TTF
#elif USE_SDL3_TTF
drawer = new TextDrawerSDL(draw);
#endif
if (drawer && !drawer->IsReady()) {
+46 -39
View File
@@ -13,10 +13,24 @@
#include "Common/Render/Text/draw_text.h"
#include "Common/Render/Text/draw_text_sdl.h"
#if defined(USE_SDL2_TTF)
#if defined(USE_SDL3_TTF)
#include "SDL2/SDL.h"
#include "SDL2/SDL_ttf.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_properties.h>
#include <SDL3_ttf/SDL_ttf.h>
static TTF_Font *OpenFontFace(const std::string &fontPath, float ptSize, int faceIndex) {
SDL_PropertiesID props = SDL_CreateProperties();
if (!props) {
return nullptr;
}
SDL_SetStringProperty(props, TTF_PROP_FONT_CREATE_FILENAME_STRING, fontPath.c_str());
SDL_SetFloatProperty(props, TTF_PROP_FONT_CREATE_SIZE_FLOAT, ptSize);
SDL_SetNumberProperty(props, TTF_PROP_FONT_CREATE_FACE_NUMBER, faceIndex);
TTF_Font *font = TTF_OpenFontWithProperties(props);
SDL_DestroyProperties(props);
return font;
}
static std::string getlocale() {
// setlocale is not an intuitive function...
@@ -31,13 +45,13 @@ static std::string getlocale() {
}
TextDrawerSDL::TextDrawerSDL(Draw::DrawContext *draw): TextDrawer(draw) {
if (TTF_Init() < 0) {
ERROR_LOG(Log::G3D, "Unable to initialize SDL2_ttf");
if (!TTF_Init()) {
ERROR_LOG(Log::G3D, "Unable to initialize SDL3_ttf");
}
dpiScale_ = CalculateDPIScale();
#if defined(USE_SDL2_TTF_FONTCONFIG)
#if defined(USE_SDL3_TTF_FONTCONFIG)
config = FcInitLoadConfigAndFonts();
#endif
@@ -50,7 +64,7 @@ TextDrawerSDL::~TextDrawerSDL() {
TTF_Quit();
#if defined(USE_SDL2_TTF_FONTCONFIG)
#if defined(USE_SDL3_TTF_FONTCONFIG)
FcConfigDestroy(config);
// Don't call this - it crashes, see https://github.com/openframeworks/openFrameworks/issues/5061.
//FcFini();
@@ -59,7 +73,7 @@ TextDrawerSDL::~TextDrawerSDL() {
// If a user complains about missing characters on SDL, re-visit this!
void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) {
#if defined(USE_SDL2_TTF_FONTCONFIG)
#if defined(USE_SDL3_TTF_FONTCONFIG)
FcObjectSet *os = FcObjectSetBuild (FC_FILE, FC_INDEX, (char *) 0);
// To install the recommended Droid Sans fallback font in Ubuntu:
@@ -189,22 +203,11 @@ void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) {
Path fontPath = Path(fontDirs[i]) / fallbackFonts[j];
if (File::Exists(fontPath)) {
TTF_Font *openedFont = TTF_OpenFont(fontPath.ToString().c_str(), 24);
int64_t numFaces = TTF_FontFaces(openedFont);
TTF_Font *openedFont = TTF_OpenFont(fontPath.ToString().c_str(), 24.0f);
int numFaces = TTF_GetNumFontFaces(openedFont);
for (int k = 0; k < numFaces; k++) {
TTF_Font *fontFace = TTF_OpenFontIndex(fontPath.ToString().c_str(), 24, k);
std::string fontFaceName(TTF_FontFaceStyleName(fontFace));
TTF_CloseFont(fontFace);
if (strstr(fontFaceName.c_str(), "Medium") ||
strstr(fontFaceName.c_str(), "Regular"))
{
fallbackFontPaths_.push_back(std::make_pair(fontPath.ToString(), k));
break;
}
fallbackFontPaths_.push_back(std::make_pair(fontPath.ToString(), k));
}
TTF_CloseFont(openedFont);
}
}
@@ -230,7 +233,7 @@ uint32_t TextDrawerSDL::CheckMissingGlyph(std::string_view text) {
uint32_t missingGlyph = 0;
while (!utf8Decoded.end()) {
uint32_t glyph = utf8Decoded.next();
if (!TTF_GlyphIsProvided32(font, glyph)) {
if (!TTF_GetGlyphMetrics(font, glyph, nullptr, nullptr, nullptr, nullptr, nullptr)) {
missingGlyph = glyph;
break;
}
@@ -249,7 +252,7 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) {
// If we encounter a missing glyph, try to use one of already loaded fallback fonts.
for (int i = 0; i < fallbackFonts_.size(); i++) {
TTF_Font *fallbackFont = fallbackFonts_[i];
if (TTF_GlyphIsProvided32(fallbackFont, missingGlyph)) {
if (TTF_GetGlyphMetrics(fallbackFont, missingGlyph, nullptr, nullptr, nullptr, nullptr, nullptr)) {
glyphFallbackFontIndex_[missingGlyph] = i;
return i;
}
@@ -261,13 +264,15 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) {
std::string& fontPath = fallbackFontPaths_[i].first;
int faceIndex = fallbackFontPaths_[i].second;
TTF_Font *font = TTF_OpenFontIndex(fontPath.c_str(), ptSize, faceIndex);
TTF_Font *font = OpenFontFace(fontPath, static_cast<float>(ptSize), faceIndex);
if (TTF_GlyphIsProvided32(font, missingGlyph)) {
if (font && TTF_GetGlyphMetrics(font, missingGlyph, nullptr, nullptr, nullptr, nullptr, nullptr)) {
fallbackFonts_.push_back(font);
return fallbackFonts_.size() - 1;
} else {
TTF_CloseFont(font);
if (font) {
TTF_CloseFont(font);
}
}
}
@@ -292,9 +297,9 @@ void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
size_t fileSz;
fileData = g_VFS.ReadFile(useFont.c_str(), &fileSz);
if (fileData) {
SDL_RWops *rw = SDL_RWFromMem(fileData, static_cast<int>(fileSz));
SDL_IOStream *rw = SDL_IOFromConstMem(fileData, fileSz);
INFO_LOG(Log::G3D, "Opened font from RW: '%p' '%d'", fileData, (int)fileSz);
font = TTF_OpenFontRW(rw, 1, ptSize);
font = TTF_OpenFontIO(rw, true, static_cast<float>(ptSize));
if (!font) {
ERROR_LOG(Log::G3D, "Failed to load font from asset file: '%s'", useFont.c_str());
}
@@ -343,7 +348,7 @@ void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float
line = " ";
}
temp = line; // zero-terminate, ugh.
TTF_SizeUTF8(font, temp.c_str(), &width, &height);
TTF_GetStringSize(font, temp.c_str(), temp.size(), &width, &height);
if (width > extW)
extW = width;
@@ -375,7 +380,7 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
std::string processedStr(str);
// If a string includes only newlines, SDL2_ttf will refuse to render it
// If a string includes only newlines, SDL3_ttf will refuse to render it
// thinking it is empty. Add a space to avoid that.
bool isAllNewline = processedStr.find_first_not_of('\n') == std::string::npos;
@@ -386,24 +391,26 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
uint32_t missingGlyph = CheckMissingGlyph(processedStr);
if (missingGlyph) {
const int ptSize = TTF_FontHeight(font) / 1.25;
const int ptSize = static_cast<int>(TTF_GetFontSize(font));
int fallbackFont = FindFallbackFonts(missingGlyph, ptSize);
if (fallbackFont >= 0 && fallbackFont < (int)fallbackFonts_.size()) {
font = fallbackFonts_[fallbackFont];
}
}
#if SDL_TTF_VERSION_ATLEAST(2, 20, 0)
if (align & ALIGN_HCENTER)
TTF_SetFontWrappedAlign(font, TTF_WRAPPED_ALIGN_CENTER);
TTF_SetFontWrapAlignment(font, TTF_HORIZONTAL_ALIGN_CENTER);
else if (align & ALIGN_RIGHT)
TTF_SetFontWrappedAlign(font, TTF_WRAPPED_ALIGN_RIGHT);
TTF_SetFontWrapAlignment(font, TTF_HORIZONTAL_ALIGN_RIGHT);
else
TTF_SetFontWrappedAlign(font, TTF_WRAPPED_ALIGN_LEFT);
#endif
TTF_SetFontWrapAlignment(font, TTF_HORIZONTAL_ALIGN_LEFT);
SDL_Color fgColor = { 0xFF, 0xFF, 0xFF, 0xFF };
SDL_Surface *text = TTF_RenderUTF8_Blended_Wrapped(font, processedStr.c_str(), fgColor, 0);
SDL_Surface *text = TTF_RenderText_Blended_Wrapped(font, processedStr.c_str(), processedStr.size(), fgColor, 0);
if (!text) {
ERROR_LOG(Log::G3D, "Failed to render SDL3_ttf text: %s", SDL_GetError());
return false;
}
SDL_LockSurface(text);
entry.texture = nullptr;
@@ -440,7 +447,7 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
}
SDL_UnlockSurface(text);
SDL_FreeSurface(text);
SDL_DestroySurface(text);
return true;
}
+6 -6
View File
@@ -5,12 +5,12 @@
#include <map>
#include "Common/Render/Text/draw_text.h"
#if defined(USE_SDL2_TTF)
#if defined(USE_SDL3_TTF)
#include "SDL2/SDL.h"
#include "SDL2/SDL_ttf.h"
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#if defined(USE_SDL2_TTF_FONTCONFIG)
#if defined(USE_SDL3_TTF_FONTCONFIG)
#include <fontconfig/fontconfig.h>
#endif
@@ -40,9 +40,9 @@ private:
std::map<int, int> glyphFallbackFontIndex_;
#if defined(USE_SDL2_TTF_FONTCONFIG)
#if defined(USE_SDL3_TTF_FONTCONFIG)
FcConfig *config;
#endif
#endif
};
#endif