💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
8.7 KiB

  1. /*
  2. * Copyright (C) 2021 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. #include "scene/text.hpp"
  20. #include "render/vertex-attribute.hpp"
  21. #include "type/unicode/convert.hpp"
  22. #include <cstddef>
  23. namespace scene {
  24. text::text():
  25. local_bounds{{0, 0, 0}, {0, 0, 0}},
  26. world_bounds{{0, 0, 0}, {0, 0, 0}},
  27. material(nullptr),
  28. font(nullptr),
  29. direction(type::text_direction::ltr),
  30. content_u8(std::string()),
  31. content_u32(std::u32string()),
  32. color({0.0f, 0.0f, 0.0f, 1.0f}),
  33. vertex_stride(0),
  34. vertex_count(0),
  35. vao(nullptr),
  36. vbo(nullptr)
  37. {
  38. // Allocate VBO and VAO
  39. vbo = new gl::vertex_buffer(0, nullptr, gl::buffer_usage::static_draw);
  40. vao = new gl::vertex_array();
  41. // Calculate vertex stride
  42. vertex_stride = (3 + 2 + 4) * sizeof(float);
  43. // Init vertex attribute offset
  44. std::size_t attribute_offset = 0;
  45. // Define vertex position attribute
  46. gl::vertex_attribute position_attribute;
  47. position_attribute.buffer = vbo;
  48. position_attribute.offset = attribute_offset;
  49. position_attribute.stride = vertex_stride;
  50. position_attribute.type = gl::vertex_attribute_type::float_32;
  51. position_attribute.components = 3;
  52. attribute_offset += position_attribute.components * sizeof(float);
  53. // Define vertex UV attribute
  54. gl::vertex_attribute uv_attribute;
  55. uv_attribute.buffer = vbo;
  56. uv_attribute.offset = attribute_offset;
  57. uv_attribute.stride = vertex_stride;
  58. uv_attribute.type = gl::vertex_attribute_type::float_32;
  59. uv_attribute.components = 2;
  60. attribute_offset += uv_attribute.components * sizeof(float);
  61. // Define vertex color attribute
  62. gl::vertex_attribute color_attribute;
  63. color_attribute.buffer = vbo;
  64. color_attribute.offset = attribute_offset;
  65. color_attribute.stride = vertex_stride;
  66. color_attribute.type = gl::vertex_attribute_type::float_32;
  67. color_attribute.components = 4;
  68. attribute_offset += color_attribute.components * sizeof(float);
  69. // Bind vertex attributes to VAO
  70. vao->bind(render::vertex_attribute::position, position_attribute);
  71. vao->bind(render::vertex_attribute::uv, uv_attribute);
  72. vao->bind(render::vertex_attribute::color, color_attribute);
  73. // Init render operation
  74. render_op.material = nullptr;
  75. render_op.bone_count = 0;
  76. render_op.skinning_palette = nullptr;
  77. render_op.vertex_array = vao;
  78. render_op.drawing_mode = gl::drawing_mode::triangles;
  79. render_op.start_index = 0;
  80. render_op.index_count = 0;
  81. render_op.instance_count = 0;
  82. }
  83. text::~text()
  84. {
  85. // Free VAO and VBO
  86. delete vao;
  87. delete vbo;
  88. }
  89. void text::render(const render::context& ctx, render::queue& queue) const
  90. {
  91. if (!vertex_count)
  92. return;
  93. render_op.transform = math::matrix_cast(get_transform_tween().interpolate(ctx.alpha));
  94. render_op.depth = ctx.clip_near.signed_distance(math::resize<3>(render_op.transform[3]));
  95. queue.push_back(render_op);
  96. }
  97. void text::refresh()
  98. {
  99. update_content();
  100. }
  101. void text::set_material(render::material* material)
  102. {
  103. this->material = material;
  104. render_op.material = material;
  105. }
  106. void text::set_font(const type::bitmap_font* font)
  107. {
  108. if (this->font != font)
  109. {
  110. this->font = font;
  111. // Update text in VBO
  112. update_content();
  113. }
  114. }
  115. void text::set_direction(type::text_direction direction)
  116. {
  117. if (this->direction != direction)
  118. {
  119. this->direction = direction;
  120. // Update text in VBO
  121. update_content();
  122. }
  123. }
  124. void text::set_content(const std::string& content)
  125. {
  126. // If content has changed
  127. if (content_u8 != content)
  128. {
  129. // Update UTF-8 content
  130. content_u8 = content;
  131. // Convert UTF-8 content to UTF-32
  132. content_u32 = type::unicode::u32(content_u8);
  133. // Update text in VBO
  134. update_content();
  135. }
  136. }
  137. void text::set_color(const float4& color)
  138. {
  139. this->color = color;
  140. // Update color in VBO
  141. update_color();
  142. }
  143. void text::transformed()
  144. {
  145. world_bounds = aabb_type::transform(local_bounds, get_transform());
  146. }
  147. void text::update_tweens()
  148. {
  149. object_base::update_tweens();
  150. if (material)
  151. {
  152. material->update_tweens();
  153. }
  154. }
  155. void text::update_content()
  156. {
  157. // If no valid font or no text, clear vertex count
  158. if (!font || content_u32.empty())
  159. {
  160. vertex_count = 0;
  161. render_op.index_count = vertex_count;
  162. local_bounds = {{0, 0, 0}, {0, 0, 0}};
  163. transformed();
  164. return;
  165. }
  166. // Calculate new vertex count and minimum vertex buffer size
  167. std::size_t vertex_count = content_u32.length() * 6;
  168. std::size_t min_vertex_buffer_size = vertex_count * vertex_stride;
  169. // Expand vertex data buffer to accommodate vertices
  170. if (vertex_data.size() < min_vertex_buffer_size)
  171. vertex_data.resize(min_vertex_buffer_size);
  172. // Get font metrics and bitmap
  173. const type::font_metrics& font_metrics = font->get_font_metrics();
  174. const image& font_bitmap = font->get_bitmap();
  175. // Init pen position
  176. float2 pen_position = {0.0f, 0.0f};
  177. // Reset local-space bounds
  178. local_bounds = {{0, 0, 0}, {0, 0, 0}};
  179. // Generate vertex data
  180. char32_t previous_code = 0;
  181. float* v = reinterpret_cast<float*>(vertex_data.data());
  182. for (char32_t code: content_u32)
  183. {
  184. // Apply kerning
  185. if (previous_code)
  186. {
  187. pen_position.x() += font->get_kerning(previous_code, code).x();
  188. }
  189. if (font->contains(code))
  190. {
  191. // Get glyph
  192. const type::bitmap_glyph& glyph = font->get_glyph(code);
  193. // Calculate vertex positions
  194. float2 positions[6];
  195. positions[0] = pen_position + glyph.metrics.horizontal_bearing;
  196. positions[1] = {positions[0].x(), positions[0].y() - glyph.metrics.height};
  197. positions[2] = {positions[0].x() + glyph.metrics.width, positions[1].y()};
  198. positions[3] = {positions[2].x(), positions[0].y()};
  199. positions[4] = positions[0];
  200. positions[5] = positions[2];
  201. // Calculate vertex UVs
  202. float2 uvs[6];
  203. uvs[0] = {static_cast<float>(glyph.position.x()), static_cast<float>(glyph.position.y())};
  204. uvs[1] = {uvs[0].x(), uvs[0].y() + glyph.metrics.height};
  205. uvs[2] = {uvs[0].x() + glyph.metrics.width, uvs[1].y()};
  206. uvs[3] = {uvs[2].x(), uvs[0].y()};
  207. uvs[4] = uvs[0];
  208. uvs[5] = uvs[2];
  209. for (int i = 0; i < 6; ++i)
  210. {
  211. // Round positions
  212. positions[i].x() = std::round(positions[i].x());
  213. positions[i].y() = std::round(positions[i].y());
  214. // Normalize UVs
  215. uvs[i].x() = uvs[i].x() / static_cast<float>(font_bitmap.get_width());
  216. uvs[i].y() = uvs[i].y() / static_cast<float>(font_bitmap.get_height());
  217. }
  218. // Add vertex to vertex data buffer
  219. for (int i = 0; i < 6; ++i)
  220. {
  221. *(v++) = positions[i].x();
  222. *(v++) = positions[i].y();
  223. *(v++) = 0.0f;
  224. *(v++) = uvs[i].x();
  225. *(v++) = uvs[i].y();
  226. *(v++) = color[0];
  227. *(v++) = color[1];
  228. *(v++) = color[2];
  229. *(v++) = color[3];
  230. }
  231. // Advance pen position
  232. pen_position.x() += glyph.metrics.horizontal_advance;
  233. // Update local-space bounds
  234. for (int i = 0; i < 4; ++i)
  235. {
  236. const float2& position = positions[i];
  237. for (int j = 0; j < 2; ++j)
  238. {
  239. local_bounds.min_point[j] = std::min<float>(local_bounds.min_point[j], position[j]);
  240. local_bounds.max_point[j] = std::max<float>(local_bounds.max_point[j], position[j]);
  241. }
  242. }
  243. }
  244. else
  245. {
  246. // Glyph not in font, zero vertex data
  247. for (std::size_t i = 0; i < (6 * 9); ++i)
  248. *(v++) = 0.0f;
  249. }
  250. // Handle newlines
  251. if (code == static_cast<char32_t>('\n'))
  252. {
  253. pen_position.x() = 0.0f;
  254. pen_position.y() -= font_metrics.linegap;
  255. }
  256. // Update previous UTF-32 character code
  257. previous_code = code;
  258. }
  259. // Resize VBO, if necessary, and upload vertex data
  260. if (vertex_count > this->vertex_count)
  261. {
  262. this->vertex_count = vertex_count;
  263. vbo->resize(min_vertex_buffer_size, vertex_data.data());
  264. }
  265. else
  266. {
  267. vbo->write(0, min_vertex_buffer_size, vertex_data.data());
  268. }
  269. // Update vertex count
  270. this->vertex_count = vertex_count;
  271. render_op.index_count = vertex_count;
  272. // Update world-space bounds
  273. transformed();
  274. }
  275. void text::update_color()
  276. {
  277. float* v = reinterpret_cast<float*>(vertex_data.data());
  278. for (std::size_t i = 0; i < vertex_count; ++i)
  279. {
  280. // Skip vertex position (vec3) and vertex UV (vec2)
  281. v += (3 + 2);
  282. // Update vertex color
  283. *(v++) = color[0];
  284. *(v++) = color[1];
  285. *(v++) = color[2];
  286. *(v++) = color[3];
  287. }
  288. // Update VBO
  289. vbo->write(0, vertex_count * vertex_stride, vertex_data.data());
  290. }
  291. } // namespace scene