Add OpenGL support in freetype fonts
All checks were successful
Run tests / Run tests (push) Successful in 6m55s

This commit is contained in:
Nikita Lisitsa 2026-07-25 03:13:09 +03:00
parent 68650da6f5
commit 04cde80596
2 changed files with 53 additions and 9 deletions

View file

@ -5,7 +5,7 @@
#include <psemek/util/span.hpp> #include <psemek/util/span.hpp>
#if defined(PSEMEK_GRAPHICS_API_OPENGL) #if defined(PSEMEK_GRAPHICS_API_OPENGL)
#error "Fonts v2 don't support OpenGL yet" #include <psemek/gfx/texture.hpp>
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) #elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
#include <psemek/wgpu/device.hpp> #include <psemek/wgpu/device.hpp>
#include <psemek/wgpu/texture_view.hpp> #include <psemek/wgpu/texture_view.hpp>
@ -29,7 +29,7 @@ namespace psemek::fonts
}; };
#if defined(PSEMEK_GRAPHICS_API_OPENGL) #if defined(PSEMEK_GRAPHICS_API_OPENGL)
// TODO using texture_type = gfx::texture_2d;
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU) #elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
using texture_type = wgpu::texture_view; using texture_type = wgpu::texture_view;
#endif #endif
@ -90,9 +90,17 @@ namespace psemek::fonts
virtual ~font_builder() {} virtual ~font_builder() {}
}; };
std::unique_ptr<font_builder> 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<font_builder> load_freetype_font(font_options const & options, std::filesystem::path const & path);
std::unique_ptr<font_builder> load_combined_freetype_font(wgpu::device device, std::vector<std::filesystem::path> const & paths); // Font paths are specified in order of priority
std::unique_ptr<font_builder> load_combined_freetype_font(font_options const & options, std::vector<std::filesystem::path> const & paths);
} }

View file

@ -71,7 +71,11 @@ namespace psemek::fonts
struct face_shared struct face_shared
{ {
#if defined(PSEMEK_GRAPHICS_API_OPENGL)
bool nearest_filter;
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
wgpu::device device; wgpu::device device;
#endif
struct face_data struct face_data
{ {
@ -81,6 +85,15 @@ namespace psemek::fonts
std::vector<face_data> faces = {}; std::vector<face_data> 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() ~face_shared()
{ {
for (auto const & face : faces) for (auto const & face : faces)
@ -151,8 +164,13 @@ namespace psemek::fonts
int current_row_height = 0; int current_row_height = 0;
int current_row_x = 0; int current_row_x = 0;
#if defined(PSEMEK_GRAPHICS_API_OPENGL)
std::unique_ptr<gfx::texture_2d> texture;
#elif defined(PSEMEK_GRAPHICS_API_WEBGPU)
wgpu::texture texture; wgpu::texture texture;
std::unique_ptr<wgpu::texture_view> texture_view; std::unique_ptr<wgpu::texture_view> texture_view;
#endif
bool needs_update = true; bool needs_update = true;
}; };
@ -274,6 +292,15 @@ namespace psemek::fonts
pages_.emplace_back(); pages_.emplace_back();
pages_.back().pixmap.resize({page_size, page_size}, 0); pages_.back().pixmap.resize({page_size, page_size}, 0);
#if defined(PSEMEK_GRAPHICS_API_OPENGL)
pages_.back().texture = std::make_unique<gfx::texture_2d>();
pages_.back().texture->load<std::uint8_t>({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({ pages_.back().texture = state_->device.create_texture({
.usage = wgpu::texture::usage::copy_dst | wgpu::texture::usage::texture_binding, .usage = wgpu::texture::usage::copy_dst | wgpu::texture::usage::texture_binding,
.dimension = wgpu::texture::dimension::_2d, .dimension = wgpu::texture::dimension::_2d,
@ -286,6 +313,7 @@ namespace psemek::fonts
.dimension = wgpu::texture_view::dimension::_2d, .dimension = wgpu::texture_view::dimension::_2d,
.usage = wgpu::texture::usage::texture_binding, .usage = wgpu::texture::usage::texture_binding,
})); }));
#endif
} }
data->page = pages_.size() - 1; data->page = pages_.size() - 1;
@ -312,7 +340,11 @@ namespace psemek::fonts
} }
auto & result = shaped_text_.emplace_back(); 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(); result.texture = pages_[data->page].texture_view.get();
#endif
result.position[0].min = pen[0] + data->offset[0]; result.position[0].min = pen[0] + data->offset[0];
result.position[0].max = result.position[0].min + data->part[0].length(); result.position[0].max = result.position[0].min + data->part[0].length();
result.position[1].min = pen[1] + data->offset[1]; result.position[1].min = pen[1] + data->offset[1];
@ -332,7 +364,11 @@ namespace psemek::fonts
if (!page.needs_update) continue; if (!page.needs_update) continue;
page.needs_update = false; 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}); 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<font_builder> load_freetype_font(wgpu::device device, std::filesystem::path const & path) std::unique_ptr<font_builder> 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<font_builder> load_combined_freetype_font(wgpu::device device, std::vector<std::filesystem::path> const & paths) std::unique_ptr<font_builder> load_combined_freetype_font(font_options const & options, std::vector<std::filesystem::path> const & paths)
{ {
auto result = std::make_shared<face_shared>(device); auto result = std::make_shared<face_shared>(options);
for (auto const & path : paths) for (auto const & path : paths)
{ {