Antkeeper  0.0.1
bitmap-font.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
22 #include <stdexcept>
23 
24 namespace type {
25 
27  font(metrics)
28 {}
29 
32 {}
33 
34 bool bitmap_font::contains(char32_t code) const
35 {
36  return m_glyphs.count(code) != 0;
37 }
38 
40 {
41  return std::get<0>(m_glyphs.try_emplace(code))->second;
42 }
43 
44 void bitmap_font::remove(char32_t code)
45 {
46  if (auto it = m_glyphs.find(code); it != m_glyphs.end())
47  {
48  m_glyphs.erase(it);
49  }
50 }
51 
53 {
54  m_glyphs.clear();
55 }
56 
57 bool bitmap_font::pack(bool resize)
58 {
59  // Returns the smallest power of two that is not smaller than @p x.
60  auto ceil2 = [](std::uint32_t x) -> std::uint32_t
61  {
62  if (x <= 1)
63  return 1;
64  std::uint32_t y = 2;
65  --x;
66  while (x >>= 1)
67  y <<= 1;
68  return y;
69  };
70 
71  // Calculate initial size of the font bitmap
72  std::uint32_t bitmap_w = 0;
73  std::uint32_t bitmap_h = 0;
74  if (resize)
75  {
76  // Find the maximum glyph dimensions
77  std::uint32_t max_glyph_w = 0;
78  std::uint32_t max_glyph_h = 0;
79  for (auto it = m_glyphs.begin(); it != m_glyphs.end(); ++it)
80  {
81  max_glyph_w = std::max(max_glyph_w, it->second.bitmap_width);
82  max_glyph_h = std::max(max_glyph_h, it->second.bitmap_height);
83  }
84 
85  // Find minimum power of two dimensions that can accommodate maximum glyph dimensions
86  bitmap_w = ceil2(max_glyph_w);
87  bitmap_h = ceil2(max_glyph_h);
88  }
89  else if (m_texture)
90  {
91  bitmap_w = m_texture->get_image_view()->get_image()->get_dimensions()[0];
92  bitmap_h = m_texture->get_image_view()->get_image()->get_dimensions()[1];
93  }
94 
95  bool packed = false;
96  geom::rect_pack<std::uint32_t> glyph_pack(bitmap_w, bitmap_h);
97  std::unordered_map<char32_t, const typename geom::rect_pack<std::uint32_t>::node_type*> glyph_map;
98 
99  while (!packed)
100  {
101  // For each glyph
102  for (auto it = m_glyphs.begin(); it != m_glyphs.end(); ++it)
103  {
104  // Attempt to pack glyph bitmap
105  const auto* node = glyph_pack.pack(it->second.bitmap_width, it->second.bitmap_height);
106 
107  // Abort if packing failed
108  if (!node)
109  break;
110 
111  // Map pack node to glyph character code
112  glyph_map[it->first] = node;
113  }
114 
115  // Check if not all glyphs were packed
116  if (glyph_map.size() != m_glyphs.size())
117  {
118  if (!resize)
119  {
120  // No resize, packing failed
121  packed = false;
122  break;
123  }
124 
125  // Clear glyph map
126  glyph_map.clear();
127 
128  // Clear glyph pack
129  glyph_pack.clear();
130 
131  // Resize glyph pack
132  if (bitmap_w > bitmap_h)
133  bitmap_h = ceil2(++bitmap_h);
134  else
135  bitmap_w = ceil2(++bitmap_w);
136  glyph_pack.resize(bitmap_w, bitmap_h);
137  }
138  else
139  {
140  packed = true;
141  }
142  }
143 
144  // Copy glyph bitmaps into font bitmap
145  if (packed)
146  {
147  // Resize bitmap font image
148  if (!m_texture ||
149  bitmap_w != m_texture->get_image_view()->get_image()->get_dimensions()[0] ||
150  bitmap_h != m_texture->get_image_view()->get_image()->get_dimensions()[1])
151  {
152 
153  // Construct font bitmap sampler
154  if (!m_sampler)
155  {
156  m_sampler = std::make_shared<gl::sampler>
157  (
163  );
164  }
165 
166  const std::uint32_t mip_count = static_cast<std::uint32_t>(std::bit_width(std::max(bitmap_w, bitmap_h)));
167  m_texture = std::make_shared<gl::texture_2d>
168  (
169  std::make_shared<gl::image_view_2d>
170  (
171  std::make_shared<gl::image_2d>
172  (
174  bitmap_w,
175  bitmap_h,
176  mip_count
177  ),
179  0,
180  mip_count
181  ),
182  m_sampler
183  );
184  }
185 
186  // For each glyph
187  for (auto it = m_glyphs.begin(); it != m_glyphs.end(); ++it)
188  {
189  // Find rect pack node corresponding to the glyph
190  const auto* node = glyph_map[it->first];
191 
192  // Write glyph bitmap data into bitmap font image
193  m_texture->get_image_view()->get_image()->write
194  (
195  0,
196  node->bounds.min.x(),
197  node->bounds.min.y(),
198  0,
199  it->second.bitmap_width,
200  it->second.bitmap_height,
201  1,
203  it->second.bitmap
204  );
205 
206  // Record coordinates of glyph bitmap within font bitmap
207  it->second.position = {node->bounds.min.x(), node->bounds.min.y()};
208  }
209 
210  // Regenerate mipmaps
211  m_texture->get_image_view()->get_image()->generate_mipmaps();
212  }
213 
214  return packed;
215 }
216 
218 {
219  if (auto it = m_glyphs.find(code); it != m_glyphs.end())
220  {
221  return it->second.metrics;
222  }
223  throw std::invalid_argument("Cannot fetch metrics of unknown bitmap glyph");
224 }
225 
226 const bitmap_glyph* bitmap_font::get_glyph(char32_t code) const
227 {
228  if (auto it = m_glyphs.find(code); it != m_glyphs.end())
229  {
230  return &it->second;
231  }
232 
233  return nullptr;
234 }
235 
237 {
238  if (auto it = m_glyphs.find(code); it != m_glyphs.end())
239  {
240  return &it->second;
241  }
242 
243  return nullptr;
244 }
245 
246 } // namespace type
Packs 2D rectangles.
Definition: rect-pack.hpp:61
const node_type * pack(scalar_type w, scalar_type h)
Packs a rect into the rect pack.
Definition: rect-pack.hpp:142
void resize(scalar_type w, scalar_type h)
Clears the pack and resizes the root node bounds.
Definition: rect-pack.hpp:127
void clear()
Clear the pack, deallocating all nodes.
Definition: rect-pack.hpp:134
Raster font in which glyphs are stored as arrays of pixels.
Definition: bitmap-font.hpp:39
bitmap_font()
Creates an empty bitmap font.
Definition: bitmap-font.cpp:30
virtual const glyph_metrics & get_glyph_metrics(char32_t code) const
Returns metrics describing a glyph.
virtual bool contains(char32_t code) const
Returns true if the font contains a glyph with the given character code.
Definition: bitmap-font.cpp:34
bool pack(bool resize=true)
Packs all glyph bitmaps into the font bitmap.
Definition: bitmap-font.cpp:57
void remove(char32_t code)
Removes a glyph from the font.
Definition: bitmap-font.cpp:44
bitmap_glyph & insert(char32_t code)
Inserts a glyph into the font.
Definition: bitmap-font.cpp:39
void clear()
Removes all glyphs from the font.
Definition: bitmap-font.cpp:52
const bitmap_glyph * get_glyph(char32_t code) const
Returns a pointer to the glyph corresponding to a UTF-32 character code, or nullptr if no such glyph ...
Abstract base class for fonts.
Definition: font.hpp:37
@ clamp_to_edge
Clamp to edge wrap mode.
@ linear
Linear filtering.
@ linear
Linear filtering.
constexpr vector< T, N > max(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the maximum elements of two vectors.
Definition: vector.hpp:1328
Text and typography.
Definition: bitmap-font.cpp:24
Single glyph in a bitmap font.
Metrics describing properties of a font.
Metrics describing properties of a glyph.