From 04cde8059653283097e9b16f2dd72f216b789ff5 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 25 Jul 2026 03:13:09 +0300 Subject: [PATCH] Add OpenGL support in freetype fonts --- libs/fonts/include/psemek/fonts/font_v2.hpp | 18 ++++++--- libs/fonts/source/freetype.cpp | 44 +++++++++++++++++++-- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/libs/fonts/include/psemek/fonts/font_v2.hpp b/libs/fonts/include/psemek/fonts/font_v2.hpp index 53639b11..cf74b4b8 100644 --- a/libs/fonts/include/psemek/fonts/font_v2.hpp +++ b/libs/fonts/include/psemek/fonts/font_v2.hpp @@ -5,7 +5,7 @@ #include #if defined(PSEMEK_GRAPHICS_API_OPENGL) -#error "Fonts v2 don't support OpenGL yet" +#include #elif defined(PSEMEK_GRAPHICS_API_WEBGPU) #include #include @@ -29,7 +29,7 @@ namespace psemek::fonts }; #if defined(PSEMEK_GRAPHICS_API_OPENGL) - // TODO + using texture_type = gfx::texture_2d; #elif defined(PSEMEK_GRAPHICS_API_WEBGPU) using texture_type = wgpu::texture_view; #endif @@ -90,9 +90,17 @@ namespace psemek::fonts virtual ~font_builder() {} }; - std::unique_ptr load_freetype_font(wgpu::device device, std::filesystem::path const & path); + struct font_options + { +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + bool nearest_filter = false; +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) + wgpu::device device; +#endif + }; - // Font paths are specified in order - std::unique_ptr load_combined_freetype_font(wgpu::device device, std::vector const & paths); + std::unique_ptr load_freetype_font(font_options const & options, std::filesystem::path const & path); + // Font paths are specified in order of priority + std::unique_ptr load_combined_freetype_font(font_options const & options, std::vector const & paths); } diff --git a/libs/fonts/source/freetype.cpp b/libs/fonts/source/freetype.cpp index 4db2eb67..431969f5 100644 --- a/libs/fonts/source/freetype.cpp +++ b/libs/fonts/source/freetype.cpp @@ -71,7 +71,11 @@ namespace psemek::fonts struct face_shared { +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + bool nearest_filter; +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) wgpu::device device; +#endif struct face_data { @@ -81,6 +85,15 @@ namespace psemek::fonts std::vector faces = {}; + face_shared(font_options const & options) + { +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + nearest_filter = options.nearest_filter; +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) + device = options.device; +#endif + } + ~face_shared() { for (auto const & face : faces) @@ -151,8 +164,13 @@ namespace psemek::fonts int current_row_height = 0; int current_row_x = 0; +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + std::unique_ptr texture; +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) wgpu::texture texture; std::unique_ptr texture_view; +#endif + bool needs_update = true; }; @@ -274,6 +292,15 @@ namespace psemek::fonts pages_.emplace_back(); pages_.back().pixmap.resize({page_size, page_size}, 0); +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + pages_.back().texture = std::make_unique(); + pages_.back().texture->load({page_size, page_size}); + if (state_->nearest_filter) + pages_.back().texture->nearest_filter(); + else + pages_.back().texture->linear_filter(); + pages_.back().texture->clamp(); +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) pages_.back().texture = state_->device.create_texture({ .usage = wgpu::texture::usage::copy_dst | wgpu::texture::usage::texture_binding, .dimension = wgpu::texture::dimension::_2d, @@ -286,6 +313,7 @@ namespace psemek::fonts .dimension = wgpu::texture_view::dimension::_2d, .usage = wgpu::texture::usage::texture_binding, })); +#endif } data->page = pages_.size() - 1; @@ -312,7 +340,11 @@ namespace psemek::fonts } auto & result = shaped_text_.emplace_back(); +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + result.texture = pages_[data->page].texture.get(); +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) result.texture = pages_[data->page].texture_view.get(); +#endif result.position[0].min = pen[0] + data->offset[0]; result.position[0].max = result.position[0].min + data->part[0].length(); result.position[1].min = pen[1] + data->offset[1]; @@ -332,7 +364,11 @@ namespace psemek::fonts if (!page.needs_update) continue; page.needs_update = false; +#if defined(PSEMEK_GRAPHICS_API_OPENGL) + page.texture->load(page.pixmap); +#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) state_->device.get_queue().write_texture({.texture = page.texture}, {(char *)page.pixmap.data(), page.pixmap.size()}, {.bytes_per_row = page_size, .rows_per_image = page_size}, {page_size, page_size, 1}); +#endif } } @@ -365,14 +401,14 @@ namespace psemek::fonts } - std::unique_ptr load_freetype_font(wgpu::device device, std::filesystem::path const & path) + std::unique_ptr load_freetype_font(font_options const & options, std::filesystem::path const & path) { - return load_combined_freetype_font(device, {path}); + return load_combined_freetype_font(options, {path}); } - std::unique_ptr load_combined_freetype_font(wgpu::device device, std::vector const & paths) + std::unique_ptr load_combined_freetype_font(font_options const & options, std::vector const & paths) { - auto result = std::make_shared(device); + auto result = std::make_shared(options); for (auto const & path : paths) {