Skip to content

Commit

Permalink
Port font to SDL3(_ttf)
Browse files Browse the repository at this point in the history
  • Loading branch information
ankith26 committed Feb 3, 2025
1 parent 02eb2ca commit a9e5f40
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 22 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/build-sdl3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ jobs:
cmake --build . --config Release --parallel
sudo cmake --install . --config Release
- name: Install SDL3_ttf
if: matrix.os != 'windows-latest'
run: |
git clone https://github.com/libsdl-org/SDL_ttf
cd SDL_ttf
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release --parallel
sudo cmake --install . --config Release
- name: Build with SDL3
run: python3 dev.py build --sdl3

Expand Down
16 changes: 16 additions & 0 deletions buildconfig/download_win_prebuilt.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ def get_urls(x86=True, x64=True):
'2d18b9a4fc2ec0eee80de2a946b088d4e6efd0ee'
],
[
'https://github.com/libsdl-org/SDL_ttf/releases/download/preview-3.1.0/SDL3_ttf-devel-3.1.0-VC.zip',
'34bb4a03c6f0f6c9de3658bac98adc7029830578'
],
[
'https://github.com/libsdl-org/SDL_mixer/releases/download/release-2.8.0/SDL2_mixer-devel-2.8.0-VC.zip',
'a10411644e08cd94f29712f430c7b71c407ae76d',
],
Expand Down Expand Up @@ -251,6 +255,18 @@ def copy(src, dst):
'SDL2_ttf-2.24.0'
)
)
copy(
os.path.join(
temp_dir,
'SDL3_ttf-devel-3.1.0-VC/SDL3_ttf-3.1.0'
),
os.path.join(
move_to_dir,
prebuilt_dir,
'SDL3_ttf-3.1.0'
)
)

copy(
os.path.join(
temp_dir,
Expand Down
1 change: 0 additions & 1 deletion dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
SDL3_ARGS = [
"-Csetup-args=-Dsdl_api=3",
"-Csetup-args=-Dmixer=disabled",
"-Csetup-args=-Dfont=disabled",
]
COVERAGE_ARGS = ["-Csetup-args=-Dcoverage=true"]

Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ if plat == 'win' and host_machine.cpu_family().startswith('x86')
sdl_ver = (sdl_api == 3) ? '3.2.2' : '2.30.12'
sdl_image_ver = (sdl_api == 3) ? '3.1.1' : '2.8.4'
sdl_mixer_ver = '2.8.0'
sdl_ttf_ver = '2.24.0'
sdl_ttf_ver = (sdl_api == 3) ? '3.1.0' : '2.24.0'

dlls = []

Expand Down
125 changes: 109 additions & 16 deletions src_c/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,11 @@ font_get_height(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontHeight(font));
#else
return PyLong_FromLong(TTF_FontHeight(font));
#endif
}

static PyObject *
Expand All @@ -180,7 +184,11 @@ font_get_descent(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontDescent(font));
#else
return PyLong_FromLong(TTF_FontDescent(font));
#endif
}

static PyObject *
Expand All @@ -191,7 +199,11 @@ font_get_ascent(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontAscent(font));
#else
return PyLong_FromLong(TTF_FontAscent(font));
#endif
}

static PyObject *
Expand All @@ -202,7 +214,11 @@ font_get_linesize(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontLineSkip(font));
#else
return PyLong_FromLong(TTF_FontLineSkip(font));
#endif
}

static PyObject *
Expand Down Expand Up @@ -453,7 +469,10 @@ font_getter_align(PyObject *self, void *closure)
return RAISE_FONT_QUIT_ERROR();
}

#if SDL_TTF_VERSION_ATLEAST(2, 20, 0)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
TTF_Font *font = PyFont_AsFont(self);
return PyLong_FromLong(TTF_GetFontWrapAlignment(font));
#elif SDL_TTF_VERSION_ATLEAST(2, 20, 0)
TTF_Font *font = PyFont_AsFont(self);
return PyLong_FromLong(TTF_GetFontWrappedAlign(font));
#else
Expand Down Expand Up @@ -492,7 +511,11 @@ font_setter_align(PyObject *self, PyObject *value, void *closure)
return -1;
}

#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
TTF_SetFontWrapAlignment(font, val);
#else
TTF_SetFontWrappedAlign(font, val);
#endif
return 0;
#else
PyErr_SetString(pgExc_SDLError,
Expand Down Expand Up @@ -611,28 +634,41 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
length string */

if (strlen(astring) == 0) { /* special 0 string case */
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
int height = TTF_GetFontHeight(font);
#else
int height = TTF_FontHeight(font);
#endif
surf = PG_CreateSurface(0, height, SDL_PIXELFORMAT_XRGB8888);
}
else { /* normal case */
if (antialias && bg_rgba_obj == Py_None) {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Blended_Wrapped(font, astring, 0, foreg,
wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf = TTF_RenderUTF8_Blended_Wrapped(font, astring, foreg,
wraplength);
#else
surf = TTF_RenderUTF8_Blended(font, astring, foreg);
#endif
}
else if (antialias) {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Shaded_Wrapped(font, astring, 0, foreg,
backg, wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf = TTF_RenderUTF8_Shaded_Wrapped(font, astring, foreg, backg,
wraplength);
#else
surf = TTF_RenderUTF8_Shaded(font, astring, foreg, backg);
#endif
}
else {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Solid_Wrapped(font, astring, 0, foreg,
wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf =
TTF_RenderUTF8_Solid_Wrapped(font, astring, foreg, wraplength);
#else
Expand All @@ -642,9 +678,16 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
resolve to Render_Solid, that needs to be explicitly handled. */
if (surf != NULL && bg_rgba_obj != Py_None) {
SDL_SetColorKey(surf, 0, 0);
surf->format->palette->colors[0].r = backg.r;
surf->format->palette->colors[0].g = backg.g;
surf->format->palette->colors[0].b = backg.b;
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
SDL_Palette *palette = SDL_GetSurfacePalette(surf);
#else
SDL_Palette *palette = surf->format->palette;
#endif
if (palette) {
palette->colors[0].r = backg.r;
palette->colors[0].g = backg.g;
palette->colors[0].b = backg.b;
}
}
}
}
Expand Down Expand Up @@ -683,15 +726,24 @@ font_size(PyObject *self, PyObject *text)
return NULL;
}
string = PyBytes_AS_STRING(bytes);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
ecode = TTF_GetStringSize(font, string, 0, &w, &h);
#else
ecode = TTF_SizeUTF8(font, string, &w, &h);
#endif
Py_DECREF(bytes);
if (ecode) {
return RAISE(pgExc_SDLError, TTF_GetError());
}
}
else if (PyBytes_Check(text)) {
string = PyBytes_AS_STRING(text);
if (TTF_SizeText(font, string, &w, &h)) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (TTF_GetStringSize(font, string, 0, &w, &h))
#else
if (TTF_SizeText(font, string, &w, &h))
#endif
{
return RAISE(pgExc_SDLError, TTF_GetError());
}
}
Expand Down Expand Up @@ -737,7 +789,13 @@ font_setter_point_size(PyFontObject *self, PyObject *value, void *closure)
return -1;
}

if (TTF_SetFontSize(font, val) == -1) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
/* TODO: can consider supporting float in python API */
if (!TTF_SetFontSize(font, (float)val))
#else
if (TTF_SetFontSize(font, val) == -1)
#endif
{
PyErr_SetString(pgExc_SDLError, SDL_GetError());
return -1;
}
Expand Down Expand Up @@ -786,7 +844,13 @@ font_set_ptsize(PyObject *self, PyObject *arg)
"point_size cannot be equal to, or less than 0");
}

if (TTF_SetFontSize(font, val) == -1) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
/* TODO: can consider supporting float in python API */
if (!TTF_SetFontSize(font, (float)val))
#else
if (TTF_SetFontSize(font, val) == -1)
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());
}
((PyFontObject *)self)->ptsize = val;
Expand All @@ -806,7 +870,11 @@ font_getter_name(PyObject *self, void *closure)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
const char *font_name = TTF_GetFontFamilyName(font);
#else
const char *font_name = TTF_FontFaceFamilyName(font);
#endif

return PyUnicode_FromString(font_name ? font_name : "");
}
Expand All @@ -819,7 +887,11 @@ font_getter_style_name(PyObject *self, void *closure)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
const char *font_style_name = TTF_GetFontStyleName(font);
#else
const char *font_style_name = TTF_FontFaceStyleName(font);
#endif
return PyUnicode_FromString(font_style_name ? font_style_name : "");
}

Expand Down Expand Up @@ -878,13 +950,19 @@ font_metrics(PyObject *self, PyObject *textobj)
for (i = 1 /* skip BOM */; i < length; i++) {
ch = buffer[i];
surrogate = Py_UNICODE_IS_SURROGATE(ch);
/* TODO:
* TTF_GlyphMetrics() seems to return a value for any character,
* using the default invalid character, if the char is not found.
*/
/* TODO:
* TTF_GlyphMetrics() seems to return a value for any character,
* using the default invalid character, if the char is not found.
*/
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!surrogate && /* conditional and */
!TTF_GetGlyphMetrics(font, (Uint16)ch, &minx, &maxx, &miny, &maxy,
&advance)) {
#else
if (!surrogate && /* conditional and */
!TTF_GlyphMetrics(font, (Uint16)ch, &minx, &maxx, &miny, &maxy,
&advance)) {
#endif
listitem =
Py_BuildValue("(iiiii)", minx, maxx, miny, maxy, advance);
if (!listitem) {
Expand Down Expand Up @@ -912,6 +990,14 @@ font_metrics(PyObject *self, PyObject *textobj)
return list;
}

/* This is taken from the harfbuzz header file. It coverts script name in the
* format expected by sdl2 (a 4 char string) to the format expected by sdl3
* a single uint32 tag */
#define HB_TAG(c1, c2, c3, c4) \
((Uint32)((((uint32_t)(c1) & 0xFF) << 24) | \
(((uint32_t)(c2) & 0xFF) << 16) | \
(((uint32_t)(c3) & 0xFF) << 8) | ((uint32_t)(c4) & 0xFF)))

static PyObject *
font_set_script(PyObject *self, PyObject *arg)
{
Expand All @@ -935,7 +1021,13 @@ font_set_script(PyObject *self, PyObject *arg)
"script code must be exactly 4 characters");
}

if (TTF_SetFontScriptName(font, script_code) < 0) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!TTF_SetFontScript(font, HB_TAG(script_code[0], script_code[1],
script_code[2], script_code[3])))
#else
if (TTF_SetFontScriptName(font, script_code) < 0)
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());
}
#else
Expand Down Expand Up @@ -1183,7 +1275,8 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)

Py_BEGIN_ALLOW_THREADS;
#if SDL_VERSION_ATLEAST(3, 0, 0)
font = TTF_OpenFontIO(rw, 1, fontsize);
/* TODO: can consider supporting float in python API */
font = TTF_OpenFontIO(rw, 1, (float)fontsize);
#else
font = TTF_OpenFontRW(rw, 1, fontsize);
#endif
Expand Down
9 changes: 8 additions & 1 deletion src_c/font.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#ifndef PGFONT_INTERNAL_H
#define PGFONT_INTERNAL_H

#include <SDL_ttf.h>
#ifdef PG_SDL3
#include <SDL3_ttf/SDL_ttf.h>

// SDL3_ttf uses SDL3 error reporting API
#define TTF_GetError SDL_GetError

#else
#include <SDL_ttf.h>
#endif
/* test font initialization */
#define FONT_INIT_CHECK() \
if (!(*(int *)PyFONT_C_API[2])) \
Expand Down
6 changes: 3 additions & 3 deletions src_c/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,6 @@ if sdl_image_dep.found()
)
endif

# TODO: support SDL3
if sdl_api != 3

if sdl_ttf_dep.found()
font = py.extension_module(
'font',
Expand All @@ -417,6 +414,9 @@ if sdl_ttf_dep.found()
)
endif

# TODO: support SDL3
if sdl_api != 3

if sdl_mixer_dep.found()
mixer = py.extension_module(
'mixer',
Expand Down

0 comments on commit a9e5f40

Please sign in to comment.