GlyphAtlas.cpp 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/QuickSort.h>
  7. #include <LibAccelGfx/GlyphAtlas.h>
  8. #include <LibGfx/Painter.h>
  9. namespace AccelGfx {
  10. GlyphAtlas& GlyphAtlas::the()
  11. {
  12. static OwnPtr<GlyphAtlas> s_the;
  13. if (!s_the)
  14. s_the = make<GlyphAtlas>();
  15. return *s_the;
  16. }
  17. void GlyphAtlas::update(HashMap<Gfx::Font const*, HashTable<u32>> const& unique_glyphs)
  18. {
  19. auto need_to_rebuild_texture = false;
  20. HashMap<GlyphsTextureKey, NonnullRefPtr<Gfx::Bitmap>> glyph_bitmaps;
  21. for (auto const& [font, code_points] : unique_glyphs) {
  22. for (auto const& code_point : code_points) {
  23. auto glyph = font->glyph(code_point);
  24. auto atlas_key = GlyphsTextureKey { font, code_point };
  25. if (!m_glyphs_texture_map.contains(atlas_key))
  26. need_to_rebuild_texture = true;
  27. if (glyph.bitmap()) {
  28. glyph_bitmaps.set(atlas_key, *glyph.bitmap());
  29. }
  30. }
  31. }
  32. if (!need_to_rebuild_texture || glyph_bitmaps.is_empty())
  33. return;
  34. m_glyphs_texture_map.clear();
  35. Vector<GlyphsTextureKey> glyphs_sorted_by_height;
  36. glyphs_sorted_by_height.ensure_capacity(glyph_bitmaps.size());
  37. for (auto const& [atlas_key, bitmap] : glyph_bitmaps) {
  38. glyphs_sorted_by_height.append(atlas_key);
  39. }
  40. quick_sort(glyphs_sorted_by_height, [&](auto const& a, auto const& b) {
  41. auto const* bitmap_a = *glyph_bitmaps.get(a);
  42. auto const* bitmap_b = *glyph_bitmaps.get(b);
  43. return bitmap_a->height() > bitmap_b->height();
  44. });
  45. int current_x = 0;
  46. int current_y = 0;
  47. int row_height = 0;
  48. int const texture_width = 512;
  49. int const padding = 1;
  50. for (auto const& glyphs_texture_key : glyphs_sorted_by_height) {
  51. auto const* bitmap = *glyph_bitmaps.get(glyphs_texture_key);
  52. if (current_x + bitmap->width() > texture_width) {
  53. current_x = 0;
  54. current_y += row_height + padding;
  55. row_height = 0;
  56. }
  57. m_glyphs_texture_map.set(glyphs_texture_key, { current_x, current_y, bitmap->width(), bitmap->height() });
  58. current_x += bitmap->width() + padding;
  59. row_height = max(row_height, bitmap->height());
  60. }
  61. auto glyphs_texture_bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { texture_width, current_y + row_height }));
  62. auto glyphs_texture_painter = Gfx::Painter(*glyphs_texture_bitmap);
  63. for (auto const& [glyphs_texture_key, glyph_bitmap] : glyph_bitmaps) {
  64. auto rect = m_glyphs_texture_map.get(glyphs_texture_key).value();
  65. glyphs_texture_painter.blit({ rect.x(), rect.y() }, glyph_bitmap, glyph_bitmap->rect());
  66. }
  67. GL::upload_texture_data(m_texture, *glyphs_texture_bitmap);
  68. }
  69. Optional<Gfx::IntRect> GlyphAtlas::get_glyph_rect(Gfx::Font const* font, u32 code_point) const
  70. {
  71. auto atlas_key = GlyphsTextureKey { font, code_point };
  72. return m_glyphs_texture_map.get(atlas_key);
  73. }
  74. }