diff --git a/test/browser/test_sdl3_ttf.c b/test/browser/test_sdl3_ttf.c new file mode 100644 index 0000000000000..fa08c71e1bae0 --- /dev/null +++ b/test/browser/test_sdl3_ttf.c @@ -0,0 +1,62 @@ +/* + * Copyright 2025 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include + +SDL_Window *window; +SDL_Renderer *renderer; +TTF_Font *font; + +#define WIDTH 640 +#define HEIGHT 480 + +void render() +{ + + SDL_Color colorA = { 0xff, 0x99, 0x00, 0xff }; + SDL_Color colorB = { 0x11, 0xff, 0xff, 0xff }; + SDL_FRect upperRect = {0, 0, WIDTH, HEIGHT / 2}; + SDL_FRect lowerRect = {0, HEIGHT / 2, WIDTH, HEIGHT / 2}; + + SDL_Surface *helloSurface = TTF_RenderText_Shaded(font, "hello", 0, colorA, colorB); + SDL_Surface *worldSurface = TTF_RenderText_Shaded(font, "world", 0, colorB, colorA); + SDL_Texture *helloTexture = SDL_CreateTextureFromSurface(renderer, helloSurface); + SDL_Texture *worldTexture = SDL_CreateTextureFromSurface(renderer, worldSurface); + + SDL_SetRenderDrawColor(renderer, 0xcc, 0xcc, 0xcc, 0xff); + SDL_RenderClear(renderer); + SDL_RenderTexture(renderer, helloTexture, NULL, &upperRect); + SDL_RenderTexture(renderer, worldTexture, NULL, &lowerRect); + SDL_RenderPresent(renderer); + + SDL_DestroySurface(helloSurface); + SDL_DestroySurface(worldSurface); + SDL_DestroyTexture(helloTexture); + SDL_DestroyTexture(worldTexture); +} + +int main(int argc, char *argv[]) +{ + SDL_Init(SDL_INIT_VIDEO); + TTF_Init(); + + if (!SDL_CreateWindowAndRenderer("SDL3 TTF", WIDTH, HEIGHT, 0, &window, &renderer)) { + printf("SDL_CreateWindowAndRenderer: %s\n", SDL_GetError()); + return 1; + } + font = TTF_OpenFont("LiberationSansBold.ttf", 40); + if (!font) { + printf("TTF_OpenFont: %s\n", SDL_GetError()); + return 1; + } + render(); + + return 0; +} diff --git a/test/browser/test_sdl3_ttf.png b/test/browser/test_sdl3_ttf.png new file mode 100644 index 0000000000000..e782a4b6d16a5 Binary files /dev/null and b/test/browser/test_sdl3_ttf.png differ diff --git a/test/browser/test_sdl3_ttf_render_text_solid.c b/test/browser/test_sdl3_ttf_render_text_solid.c new file mode 100644 index 0000000000000..6eb5ec6390449 --- /dev/null +++ b/test/browser/test_sdl3_ttf_render_text_solid.c @@ -0,0 +1,37 @@ +/* + * Copyright 2025 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int width = 320; + int height = 48; + + SDL_Init(SDL_INIT_VIDEO); + SDL_Window *window = SDL_CreateWindow("SDL3 TTF Render Text Solid", width, height, 0); + SDL_Surface *screen = SDL_GetWindowSurface(window); + + TTF_Init(); + TTF_Font *font = TTF_OpenFont("LiberationSansBold.ttf", 32); + if (!font) { + printf("TTF_OpenFont: %s\n", SDL_GetError()); + return 1; + } + + SDL_Color color = { 0xff, 0x99, 0x00, 0xff }; + SDL_Surface *text = TTF_RenderText_Solid(font, "Play", 0, color); + + SDL_FillSurfaceRect(screen, NULL, SDL_MapRGB(SDL_GetPixelFormatDetails(screen->format), NULL, 255, 0, 0)); + SDL_BlitSurface(text, NULL, screen, NULL); + SDL_UpdateWindowSurface(window); + + return 0; +} diff --git a/test/browser/test_sdl3_ttf_render_text_solid.png b/test/browser/test_sdl3_ttf_render_text_solid.png new file mode 100644 index 0000000000000..2f42860921b79 Binary files /dev/null and b/test/browser/test_sdl3_ttf_render_text_solid.png differ diff --git a/test/browser/test_sdl_ttf_render_text_solid.c b/test/browser/test_sdl_ttf_render_text_solid.c index a9f3788913d75..2962b1e7b79db 100644 --- a/test/browser/test_sdl_ttf_render_text_solid.c +++ b/test/browser/test_sdl_ttf_render_text_solid.c @@ -11,16 +11,16 @@ int main() { - SDL_Init(SDL_INIT_VIDEO); - SDL_Surface *screen = SDL_SetVideoMode(320, 32, 32, SDL_HWSURFACE); - - TTF_Init(); - TTF_Font *font = TTF_OpenFont("Arial", 32); - - SDL_Color color = { 0xff, 0x99, 0x00, 0xff }; - SDL_Surface *text = TTF_RenderText_Solid(font, "Play", color); - SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 0, 0)); - SDL_BlitSurface(text, NULL, screen, NULL); - return 0; + SDL_Init(SDL_INIT_VIDEO); + SDL_Surface *screen = SDL_SetVideoMode(320, 32, 32, SDL_HWSURFACE); + + TTF_Init(); + TTF_Font *font = TTF_OpenFont("Arial", 32); + + SDL_Color color = { 0xff, 0x99, 0x00, 0xff }; + SDL_Surface *text = TTF_RenderText_Solid(font, "Play", color); + SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 0, 0)); + SDL_BlitSurface(text, NULL, screen, NULL); + + return 0; } - diff --git a/test/test_browser.py b/test/test_browser.py index a934191bc7ddb..c2a35a3003407 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2247,6 +2247,14 @@ def test_sdl_canvas_palette_2(self): def test_sdl_ttf_render_text_solid(self): self.reftest('test_sdl_ttf_render_text_solid.c', 'test_sdl_ttf_render_text_solid.png', cflags=['-O2', '-lSDL', '-lGL']) + def test_sdl3_ttf_render_text_solid(self): + self.cflags.append('-Wno-experimental') + shutil.copy2(test_file('freetype/LiberationSansBold.ttf'), self.get_dir()) + self.reftest('test_sdl3_ttf_render_text_solid.c', 'test_sdl3_ttf_render_text_solid.png', + cflags=[ + '-O2', '-sUSE_SDL=3', '-sUSE_SDL_TTF=3', '-lGL', + '--embed-file', 'LiberationSansBold.ttf']) + def test_sdl_alloctext(self): self.btest_exit('test_sdl_alloctext.c', cflags=['-lSDL', '-lGL']) @@ -3211,6 +3219,12 @@ def test_sdl2_ttf(self): self.reftest('test_sdl2_ttf.c', 'test_sdl2_ttf.png', cflags=['-O2', '-sUSE_SDL=2', '-sUSE_SDL_TTF=2', '--embed-file', 'LiberationSansBold.ttf']) + @requires_graphics_hardware + def test_sdl3_ttf(self): + shutil.copy2(test_file('freetype/LiberationSansBold.ttf'), self.get_dir()) + self.reftest('test_sdl3_ttf.c', 'test_sdl3_ttf.png', + cflags=['-O2', '-sUSE_SDL=3', '-sUSE_SDL_TTF=3', '--embed-file', 'LiberationSansBold.ttf']) + @requires_graphics_hardware def test_sdl2_ttf_rtl(self): shutil.copy2(test_file('third_party/notofont/NotoNaskhArabic-Regular.ttf'), self.get_dir()) diff --git a/test/test_other.py b/test/test_other.py index 4ce2b8b3960a1..92bca5a6a29a5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2617,6 +2617,12 @@ def test_sdl2_ttf(self): self.emcc(test_file('browser/test_sdl2_ttf.c'), args=['-sUSE_SDL=2', '-sUSE_SDL_TTF=2'], output_filename='a.out.js') self.emcc(test_file('browser/test_sdl2_ttf.c'), args=['--use-port=sdl2', '--use-port=sdl2_ttf'], output_filename='a.out.js') + @requires_network + def test_sdl3_ttf(self): + # A compile-only test that checks if sdl3-ttf, and dependencies freetype and harfbuzz, are buildable. + self.emcc(test_file('browser/test_sdl3_ttf.c'), args=['-sUSE_SDL=3', '-sUSE_SDL_TTF=3'], output_filename='a.out.js') + self.emcc(test_file('browser/test_sdl3_ttf.c'), args=['--use-port=sdl3', '--use-port=sdl3_ttf'], output_filename='a.out.js') + @requires_network def test_contrib_ports(self): # Verify that contrib ports can be used (using the only contrib port available ATM, but can be replaced diff --git a/test/test_sdl3_ttf.c b/test/test_sdl3_ttf.c new file mode 100644 index 0000000000000..ec4c70edab314 --- /dev/null +++ b/test/test_sdl3_ttf.c @@ -0,0 +1,27 @@ +/* + * Copyright 2025 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +int main() { + SDL_Init(SDL_INIT_VIDEO); + + if (!TTF_Init()) { + printf("TTF_Init: %s\n", SDL_GetError()); + return 1; + } + + TTF_Quit(); + SDL_Quit(); + + return 0; +} diff --git a/tools/ports/sdl3_ttf.py b/tools/ports/sdl3_ttf.py new file mode 100644 index 0000000000000..fe145b2dbcd5f --- /dev/null +++ b/tools/ports/sdl3_ttf.py @@ -0,0 +1,63 @@ +# Copyright 2025 The Emscripten Authors. All rights reserved. +# Emscripten is available under two separate licenses, the MIT license and the +# University of Illinois/NCSA Open Source License. Both these licenses can be +# found in the LICENSE file. + +import os + +TAG = 'release-3.2.2' +HASH = 'c5f34d1b79492e0341c91687cde9ec315f5d6544c7ebaa7ef5d092e77ccfc363a0e702ba9c43bfa0926c54420843ccfb98b81362985fd7b4a67d09a7852b90ba' + +deps = ['freetype', 'sdl3', 'harfbuzz'] + +variants = {'sdl3_ttf-mt': {'PTHREADS': 1}} + + +def needed(settings): + return settings.USE_SDL_TTF == 3 + + +def get_lib_name(settings): + return 'libSDL3_ttf' + ('-mt' if settings.PTHREADS else '') + '.a' + + +def get(ports, settings, shared): + ports.fetch_project('sdl3_ttf', f'https://github.com/libsdl-org/SDL_ttf/archive/{TAG}.zip', sha512hash=HASH) + + def create(final): + src_root = ports.get_dir('sdl3_ttf', 'SDL_ttf-' + TAG) + ports.install_header_dir(os.path.join(src_root, 'include'), target='.') + flags = ['-DTTF_USE_HARFBUZZ=1', '-sUSE_SDL=3', '-sUSE_FREETYPE', '-sUSE_HARFBUZZ'] + if settings.PTHREADS: + flags += ['-pthread'] + + srcs = [ + 'src/SDL_gpu_textengine.c', + 'src/SDL_hashtable.c', + 'src/SDL_hashtable_ttf.c', + 'src/SDL_renderer_textengine.c', + 'src/SDL_surface_textengine.c', + 'src/SDL_ttf.c', + ] + + ports.build_port(src_root, final, 'sdl3_ttf', flags=flags, srcs=srcs) + + return [shared.cache.get_lib(get_lib_name(settings), create, what='port')] + + +def clear(ports, settings, shared): + shared.cache.erase_lib(get_lib_name(settings)) + + +def process_dependencies(settings): + settings.USE_SDL = 3 + settings.USE_FREETYPE = 1 + settings.USE_HARFBUZZ = 1 + + +def process_args(ports): + return ['-DTTF_USE_HARFBUZZ=1'] + + +def show(): + return 'sdl3_ttf (-sUSE_SDL_TTF=3 or --use-port=sdl3_ttf; zlib license)'