Unravel Engine C++ Reference
Loading...
Searching...
No Matches
text_buffer_manager.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 Jeremie Roy. All rights reserved.
3 * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
4 */
5
6#include "../common.h"
7
8#include <bgfx/bgfx.h>
9#include <bgfx/embedded_shader.h>
10
11#include <cmath>
12#include <stddef.h> // offsetof
13#include <wchar.h> // wcslen
14
15#include "../cube_atlas.h"
16#include "text_buffer_manager.h"
17#include "utf8.h"
18
19#include <tinystl/allocator.h>
20#include <tinystl/unordered_map.h>
21#include <tinystl/vector.h>
22namespace stl = tinystl;
23
24#include "fs_font_basic.bin.h"
32#include "vs_font_basic.bin.h"
40
41namespace gfx
42{
43
44static const bgfx::EmbeddedShader s_embedded_shaders[] = {
45 BGFX_EMBEDDED_SHADER(vs_font_basic),
46 BGFX_EMBEDDED_SHADER(fs_font_basic),
47 BGFX_EMBEDDED_SHADER(vs_font_distance_field),
48 BGFX_EMBEDDED_SHADER(fs_font_distance_field),
49 BGFX_EMBEDDED_SHADER(vs_font_distance_field_subpixel),
50 BGFX_EMBEDDED_SHADER(fs_font_distance_field_subpixel),
51 BGFX_EMBEDDED_SHADER(vs_font_distance_field_outline),
52 BGFX_EMBEDDED_SHADER(fs_font_distance_field_outline),
53 BGFX_EMBEDDED_SHADER(vs_font_distance_field_outline_image),
54 BGFX_EMBEDDED_SHADER(fs_font_distance_field_outline_image),
55 BGFX_EMBEDDED_SHADER(vs_font_distance_field_drop_shadow),
56 BGFX_EMBEDDED_SHADER(fs_font_distance_field_drop_shadow),
57 BGFX_EMBEDDED_SHADER(vs_font_distance_field_drop_shadow_image),
58 BGFX_EMBEDDED_SHADER(fs_font_distance_field_drop_shadow_image),
59 BGFX_EMBEDDED_SHADER(vs_font_distance_field_outline_drop_shadow_image),
60 BGFX_EMBEDDED_SHADER(fs_font_distance_field_outline_drop_shadow_image),
61
62 BGFX_EMBEDDED_SHADER_END()};
63
65{
66public:
67 text_buffer(font_manager* manager) : font_manager_(manager)
68 {
69 size_t initial(8192 - 5);
70 resize_buffers(initial);
71 }
72
73 void resize_buffers(size_t max_buffered_characters)
74 {
75 vertex_buffer_.resize(max_buffered_characters * 4);
76 index_buffer_.resize(max_buffered_characters * 6);
77 style_buffer_.resize(max_buffered_characters * 4);
78 }
79
80 auto get_max_buffered_characters() const -> size_t
81 {
82 return vertex_buffer_.size() / 4;
83 }
84
85 auto get_outline_color() -> uint32_t
86 {
87 return outline_color_;
88 }
89
90 auto get_outline_width() -> float
91 {
92 return outline_width_;
93 }
94
95 auto get_drop_shadow_color() -> uint32_t
96 {
97 return drop_shadow_color_;
98 }
99
101 {
102 return drop_shadow_offset_[0];
103 }
104
106 {
107 return drop_shadow_offset_[1];
108 }
109
111 {
112 return drop_shadow_softener_;
113 }
114
115 void set_style(uint32_t flags = style_normal)
116 {
117 style_flags_ = flags;
118 }
119
120 void set_text_color(uint32_t rgba = 0xff000000)
121 {
122 text_color_ = rgba;
123 }
124
125 void set_background_color(uint32_t rgba = 0xff000000)
126 {
127 background_color_ = rgba;
128 }
129
130 void set_foreground_color(uint32_t rgba = 0xff000000)
131 {
132 foreground_color_ = rgba;
133 }
134
135 void set_overline_color(uint32_t rgba = 0xff000000)
136 {
137 overline_color_ = rgba;
138 }
139
140 void set_underline_color(uint32_t rgba = 0xff000000)
141 {
142 underline_color_ = rgba;
143 }
144
145 void set_strike_through_color(uint32_t rgba = 0xff000000)
146 {
147 strike_through_color_ = rgba;
148 }
149
150 void set_outline_color(uint32_t rgba = 0xff000000)
151 {
152 outline_color_ = rgba;
153 }
154
155 void set_outline_width(float outline_width = 3.0f)
156 {
157 outline_width_ = outline_width;
158 }
159
160 void set_drop_shadow_color(uint32_t rgba = 0xff000000)
161 {
162 drop_shadow_color_ = rgba;
163 }
164
165 void set_drop_shadow_offset(float u, float v)
166 {
167 drop_shadow_offset_[0] = u;
168 drop_shadow_offset_[1] = v;
169 }
170
171 void set_drop_shadow_softener(float smoother)
172 {
173 drop_shadow_softener_ = smoother;
174 }
175
176 void set_pen_position(float x, float y)
177 {
178 pen_x_ = x;
179 pen_y_ = y;
180 }
181
182 void get_pen_position(float* x, float* y)
183 {
184 *x = pen_x_;
185 *y = pen_y_;
186 }
187
188 void set_pen_origin(float x, float y)
189 {
190 origin_x_ = x;
191 origin_y_ = y;
192 }
193
194 void set_apply_kerning(bool apply_kerning)
195 {
196 apply_kerning_ = apply_kerning;
197 }
198
199 void append_text(font_handle font_handle, const char* str, const char* end = nullptr);
200
201 void append_text(font_handle font_handle, const wchar_t* str, const wchar_t* end = nullptr);
202
203 void append_atlas_face(font_handle font_handle, uint16_t face_index);
204
205 void clear_text_buffer();
206
207 auto get_vertex_buffer() -> const uint8_t*
208 {
209 return (uint8_t*)vertex_buffer_.data();
210 }
211
212 auto get_vertex_count() const -> uint32_t
213 {
214 return vertex_count_;
215 }
216
217 auto get_vertex_size() const -> uint32_t
218 {
219 return sizeof(text_vertex);
220 }
221
222 auto get_index_buffer() const -> const uint16_t*
223 {
224 return index_buffer_.data();
225 }
226
227 auto get_buffers_dirty() const -> bool
228 {
229 return buffers_dirty_;
230 }
231
232 void set_buffers_dirty(bool dirty)
233 {
234 buffers_dirty_ = dirty;
235 }
236
237 auto get_index_count() const -> uint32_t
238 {
239 return index_count_;
240 }
241
242 auto get_index_size() const -> uint32_t
243 {
244 return sizeof(uint16_t);
245 }
246
247 auto get_text_color() const -> uint32_t
248 {
249 return text_color_;
250 }
251
253 {
254 return rectangle_;
255 }
256
257private:
258 void append_glyph(font_handle handle, code_point codepoint, bool shadow);
259 void vertical_center_last_line(float dy, float top, float bottom);
260
261 static auto to_abgr(uint32_t rgba) -> uint32_t
262 {
263 return (((rgba >> 0) & 0xff) << 24) | (((rgba >> 8) & 0xff) << 16) | (((rgba >> 16) & 0xff) << 8) |
264 (((rgba >> 24) & 0xff) << 0);
265 }
266
267 void set_vertex(uint32_t i, float x, float y, uint32_t rgba, uint8_t style = style_normal)
268 {
269 vertex_buffer_[i].x = x;
270 vertex_buffer_[i].y = y;
271 vertex_buffer_[i].rgba = rgba;
272 style_buffer_[i] = style;
273 }
274
275 void set_outline_color(uint32_t i, uint32_t rgba_outline)
276 {
277 vertex_buffer_[i].rgba_outline = rgba_outline;
278 }
279
280 struct text_vertex
281 {
282 float x{}, y{};
283 int16_t u{}, v{}, w{}, t{};
284 int16_t u1{}, v1{}, w1{}, t1{};
285 int16_t u2{}, v2{}, w2{}, t2{};
286 uint32_t rgba{};
287 uint32_t rgba_outline{};
288 };
289
290 uint32_t style_flags_{style_normal};
291
292 uint32_t text_color_{0xffffffff};
293 uint32_t background_color_{0x00000000};
294 uint32_t foreground_color_{0x00000000};
295 uint32_t overline_color_{0xffffffff};
296 uint32_t underline_color_{0xffffffff};
297 uint32_t strike_through_color_{0xffffffff};
298
299 float outline_width_{0.0f};
300 uint32_t outline_color_{0xff000000};
301
302 float drop_shadow_offset_[2] = {0.00f, 0.00f};
303 uint32_t drop_shadow_color_{0xff000000};
304 float drop_shadow_softener_{1.0f};
305
306 bool apply_kerning_{true};
307 float pen_x_{};
308 float pen_y_{};
309
310 float origin_x_{};
311 float origin_y_{};
312
313 float line_ascender_{};
314 float line_descender_{};
315 float line_gap_{};
316
317 code_point previous_code_point_{};
318
319 text_rectangle rectangle_{};
320 font_manager* font_manager_;
321
322 stl::vector<text_vertex> vertex_buffer_;
323 stl::vector<uint16_t> index_buffer_;
324 stl::vector<uint8_t> style_buffer_;
325
326 bool buffers_dirty_{};
327
328 uint32_t index_count_{};
329 uint32_t line_start_index_{};
330 uint16_t vertex_count_{};
331};
332
333
334void text_buffer::append_text(font_handle handle, const char* str, const char* end)
335{
336 if(vertex_count_ == 0)
337 {
338 line_descender_ = 0;
339 line_ascender_ = 0;
340 line_gap_ = 0;
341 previous_code_point_ = 0;
342 }
343
344 code_point codepoint = 0;
345 uint32_t state = 0;
346
347 if(end == nullptr)
348 {
349 end = str + bx::strLen(str);
350 }
351 BX_ASSERT(end >= str, "");
352
353 const font_info& font = font_manager_->get_font_info(handle);
355 {
356 float save_pen_x = pen_x_;
357 float save_pen_y = pen_y_;
358 code_point save_previous_code_point = previous_code_point_;
359 text_rectangle save_rectangle = rectangle_;
360
361 const char* orig_string = str;
362 for(; *str && str < end; ++str)
363 {
364 if(utf8_decode(&state, &codepoint, *str) == UTF8_ACCEPT)
365 {
366 append_glyph(handle, codepoint, true);
367 }
368 }
369 str = orig_string;
370
371 pen_x_ = save_pen_x;
372 pen_y_ = save_pen_y;
373 previous_code_point_ = save_previous_code_point;
374 rectangle_ = save_rectangle;
375 }
376
377 for(; *str && str < end; ++str)
378 {
379 if(utf8_decode(&state, &codepoint, *str) == UTF8_ACCEPT)
380 {
381 append_glyph(handle, codepoint, false);
382 }
383 }
384
385 BX_ASSERT(state == UTF8_ACCEPT, "The string is not well-formed");
386}
387
388void text_buffer::append_text(font_handle handle, const wchar_t* str, const wchar_t* end)
389{
390 if(vertex_count_ == 0)
391 {
392 line_descender_ = 0;
393 line_ascender_ = 0;
394 line_gap_ = 0;
395 previous_code_point_ = 0;
396 }
397
398 if(end == nullptr)
399 {
400 end = str + wcslen(str);
401 }
402 BX_ASSERT(end >= str, "");
403
404 const font_info& font = font_manager_->get_font_info(handle);
406 {
407 float save_pen_x = pen_x_;
408 float save_pen_y = pen_y_;
409 code_point save_previous_code_point = previous_code_point_;
410 text_rectangle save_rectangle = rectangle_;
411
412 for(const wchar_t* current = str; current < end; ++current)
413 {
414 code_point code_point = *current;
415 append_glyph(handle, code_point, true);
416 }
417
418 pen_x_ = save_pen_x;
419 pen_y_ = save_pen_y;
420 previous_code_point_ = save_previous_code_point;
421 rectangle_ = save_rectangle;
422 }
423
424 for(const wchar_t* current = str; current < end; ++current)
425 {
426 code_point code_point = *current;
427 append_glyph(handle, code_point, false);
428 }
429}
430
431void text_buffer::append_atlas_face(font_handle handle, uint16_t face_index)
432{
433 if(vertex_count_ / 4 >= get_max_buffered_characters())
434 {
435 //background
436 size_t max_quads_per_glyph = 1;
437 size_t capacity_growth = 10;
438 resize_buffers(get_max_buffered_characters() + max_quads_per_glyph * capacity_growth);
439 }
440
441 const Atlas* atlas = font_manager_->get_atlas(handle);
442
443 float x0 = pen_x_;
444 float y0 = pen_y_;
445 float x1 = x0 + (float)atlas->getTextureSize();
446 float y1 = y0 + (float)atlas->getTextureSize();
447
448 atlas->packFaceLayerUV(face_index,
449 (uint8_t*)vertex_buffer_.data(),
450 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
451 sizeof(text_vertex));
452
453 set_vertex(vertex_count_ + 0, x0, y0, background_color_);
454 set_vertex(vertex_count_ + 1, x0, y1, background_color_);
455 set_vertex(vertex_count_ + 2, x1, y1, background_color_);
456 set_vertex(vertex_count_ + 3, x1, y0, background_color_);
457
458 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
459 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
460 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
461 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
462 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
463 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
464 vertex_count_ += 4;
465 index_count_ += 6;
466 buffers_dirty_ = true;
467
468 pen_x_ += x1 - x0;
469}
470
472{
473 pen_x_ = 0;
474 pen_y_ = 0;
475 origin_x_ = 0;
476 origin_y_ = 0;
477
478 vertex_count_ = 0;
479 index_count_ = 0;
480 line_start_index_ = 0;
481 line_ascender_ = 0;
482 line_descender_ = 0;
483 line_gap_ = 0;
484 previous_code_point_ = 0;
485 rectangle_.width = 0;
486 rectangle_.height = 0;
487}
488
489void text_buffer::append_glyph(font_handle handle, code_point codepoint, bool shadow)
490{
491 if(codepoint == L'\t')
492 {
493 for(uint32_t ii = 0; ii < 4; ++ii)
494 {
495 append_glyph(handle, L' ', shadow);
496 }
497 return;
498 }
499
500 const glyph_info* glyph = font_manager_->get_glyph_info(handle, codepoint);
501 BX_WARN(NULL != glyph, "Glyph not found (font handle %d, code point %d)", handle.idx, codepoint);
502 if(nullptr == glyph)
503 {
504 previous_code_point_ = 0;
505 return;
506 }
507
508 if(vertex_count_ / 4 >= get_max_buffered_characters())
509 {
510 // background, shadow, underline, overline, glyph, foreground
511 size_t max_quads_per_glyph = 6;
512 size_t capacity_growth = 100;
513 resize_buffers(get_max_buffered_characters() + max_quads_per_glyph * capacity_growth);
514 }
515
516 const font_info& font = font_manager_->get_font_info(handle);
517
518 if(codepoint == L'\n')
519 {
520 line_gap_ = font.line_gap;
521 line_descender_ = font.descender;
522 line_ascender_ = font.ascender;
523 line_start_index_ = vertex_count_;
524 previous_code_point_ = 0;
525 pen_x_ = origin_x_;
526 pen_y_ += line_gap_ + line_ascender_ - line_descender_;
527 return;
528 }
529
530 // is there a change of font size that require the text on the left to be centered again ?
531 if(font.ascender > line_ascender_ || (font.descender < line_descender_))
532 {
533 if(font.descender < line_descender_)
534 {
535 line_descender_ = font.descender;
536 line_gap_ = font.line_gap;
537 }
538
539 float txtDecals = (font.ascender - line_ascender_);
540 line_ascender_ = font.ascender;
541 line_gap_ = font.line_gap;
542 vertical_center_last_line((txtDecals),
543 (pen_y_ - line_ascender_),
544 (pen_y_ + line_ascender_ - line_descender_ + line_gap_));
545 }
546
547 float kerning = 0.0f;
548 if(apply_kerning_)
549 {
550 kerning = font_manager_->get_kerning(handle, previous_code_point_, codepoint);
551 pen_x_ += kerning;
552 }
553
554 const glyph_info& whiteGlyph = font_manager_->get_white_glyph(handle);
555 const Atlas* atlas = font_manager_->get_atlas(handle);
556 const AtlasRegion& atlasRegion = atlas->getRegion(glyph->region_index);
557
558 const bool is_drop_shadow_font =
559 (font_manager_->get_font_info(handle).font_type & FONT_TYPE_MASK_DISTANCE_DROP_SHADOW) != 0;
560
561 if((shadow || !is_drop_shadow_font) && style_flags_ & style_background && background_color_ & 0xff000000)
562 {
563 float x0 = pen_x_ - kerning;
564 float y0 = pen_y_;
565 float x1 = x0 + glyph->advance_x;
566 float y1 = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
567
568 atlas->packUV(whiteGlyph.region_index,
569 (uint8_t*)vertex_buffer_.data(),
570 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
571 sizeof(text_vertex));
572
573 set_vertex(vertex_count_ + 0, x0, y0, background_color_, style_background);
574 set_vertex(vertex_count_ + 1, x0, y1, background_color_, style_background);
575 set_vertex(vertex_count_ + 2, x1, y1, background_color_, style_background);
576 set_vertex(vertex_count_ + 3, x1, y0, background_color_, style_background);
577
578 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
579 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
580 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
581 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
582 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
583 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
584 vertex_count_ += 4;
585 index_count_ += 6;
586 buffers_dirty_ = true;
587
588 }
589
590 if(shadow)
591 {
592 if(atlasRegion.getType() != AtlasRegion::TYPE_BGRA8)
593 {
594 float extra_x_offset = drop_shadow_offset_[0] * font.scale;
595 float extra_y_offset = drop_shadow_offset_[1] * font.scale;
596
597 uint32_t adjusted_drop_shadow_color =
598 ((((drop_shadow_color_ & 0xff000000) >> 8) * (text_color_ >> 24)) & 0xff000000) |
599 (drop_shadow_color_ & 0x00ffffff);
600
601 const uint8_t shadowA = (drop_shadow_color_ >> 24) & 0xFF;
602
603 if(shadowA > 0 || std::fabs(extra_x_offset) > 1e-6f || std::fabs(extra_y_offset) > 1e-6f)
604 {
605 float x0 = pen_x_ + glyph->offset_x + extra_x_offset;
606 float y0 = pen_y_ + line_ascender_ + glyph->offset_y + extra_y_offset;
607 float x1 = x0 + glyph->width;
608 float y1 = y0 + glyph->height;
609
610 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
611
612 atlas->packUV(glyph->region_index,
613 (uint8_t*)vertex_buffer_.data(),
614 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u2),
615 sizeof(text_vertex));
616
617 set_vertex(vertex_count_ + 0, x0, y0, adjusted_drop_shadow_color);
618 set_vertex(vertex_count_ + 1, x0, y1, adjusted_drop_shadow_color);
619 set_vertex(vertex_count_ + 2, x1, y1, adjusted_drop_shadow_color);
620 set_vertex(vertex_count_ + 3, x1, y0, adjusted_drop_shadow_color);
621
622 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
623 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
624 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
625 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
626 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
627 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
628 vertex_count_ += 4;
629 index_count_ += 6;
630 buffers_dirty_ = true;
631
632 }
633 }
634
635 pen_x_ += glyph->advance_x;
636
637 float lineWidth = pen_x_ - origin_x_;
638 if(lineWidth > rectangle_.width)
639 {
640 rectangle_.width = lineWidth;
641 }
642
643 float lineHeight = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
644 if(lineHeight > rectangle_.height)
645 {
646 rectangle_.height = lineHeight;
647 }
648
649 previous_code_point_ = codepoint;
650
651 return;
652 }
653
654 if(style_flags_ & style_underline && underline_color_ & 0xFF000000)
655 {
656 float x0 = pen_x_ - kerning;
657 float y0 = pen_y_ + line_ascender_ - line_descender_ * 0.5f;
658 float x1 = x0 + glyph->advance_x;
659 float y1 = y0 + font.underline_thickness;
660
661 atlas->packUV(whiteGlyph.region_index,
662 (uint8_t*)vertex_buffer_.data(),
663 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
664 sizeof(text_vertex));
665
666 set_vertex(vertex_count_ + 0, x0, y0, underline_color_, style_underline);
667 set_vertex(vertex_count_ + 1, x0, y1, underline_color_, style_underline);
668 set_vertex(vertex_count_ + 2, x1, y1, underline_color_, style_underline);
669 set_vertex(vertex_count_ + 3, x1, y0, underline_color_, style_underline);
670
671 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
672 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
673 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
674 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
675 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
676 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
677 vertex_count_ += 4;
678 index_count_ += 6;
679 buffers_dirty_ = true;
680
681 }
682
683 if(style_flags_ & style_overline && overline_color_ & 0xFF000000)
684 {
685 float x0 = pen_x_ - kerning;
686 float y0 = pen_y_;
687 float x1 = x0 + glyph->advance_x;
688 float y1 = y0 + font.underline_thickness;
689
690 atlas->packUV(whiteGlyph.region_index,
691 (uint8_t*)vertex_buffer_.data(),
692 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
693 sizeof(text_vertex));
694
695 set_vertex(vertex_count_ + 0, x0, y0, overline_color_, style_overline);
696 set_vertex(vertex_count_ + 1, x0, y1, overline_color_, style_overline);
697 set_vertex(vertex_count_ + 2, x1, y1, overline_color_, style_overline);
698 set_vertex(vertex_count_ + 3, x1, y0, overline_color_, style_overline);
699
700 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
701 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
702 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
703 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
704 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
705 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
706 vertex_count_ += 4;
707 index_count_ += 6;
708 buffers_dirty_ = true;
709
710 }
711
712 if(!shadow && atlasRegion.getType() == AtlasRegion::TYPE_BGRA8)
713 {
714 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
715
716 atlas->packUV(glyph->region_index,
717 (uint8_t*)vertex_buffer_.data(),
718 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u1),
719 sizeof(text_vertex));
720
721 float glyph_scale = glyph->bitmap_scale;
722 float glyph_width = glyph->width * glyph_scale;
723 float glyph_height = glyph->height * glyph_scale;
724 float x0 = pen_x_ + glyph->offset_x;
725 float y0 = pen_y_ + (font.ascender + -font.descender - glyph_height) / 2;
726 float x1 = x0 + glyph_width;
727 float y1 = y0 + glyph_height;
728
729 set_vertex(vertex_count_ + 0, x0, y0, text_color_);
730 set_vertex(vertex_count_ + 1, x0, y1, text_color_);
731 set_vertex(vertex_count_ + 2, x1, y1, text_color_);
732 set_vertex(vertex_count_ + 3, x1, y0, text_color_);
733 }
734 else if(!shadow)
735 {
736 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
737
738 atlas->packUV(glyph->region_index,
739 (uint8_t*)vertex_buffer_.data(),
740 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
741 sizeof(text_vertex));
742
743 float x0 = pen_x_ + glyph->offset_x;
744 float y0 = pen_y_ + line_ascender_ + glyph->offset_y;
745 float x1 = x0 + glyph->width;
746 float y1 = y0 + glyph->height;
747
748 set_vertex(vertex_count_ + 0, x0, y0, text_color_);
749 set_vertex(vertex_count_ + 1, x0, y1, text_color_);
750 set_vertex(vertex_count_ + 2, x1, y1, text_color_);
751 set_vertex(vertex_count_ + 3, x1, y0, text_color_);
752
753 set_outline_color(vertex_count_ + 0, outline_color_);
754 set_outline_color(vertex_count_ + 1, outline_color_);
755 set_outline_color(vertex_count_ + 2, outline_color_);
756 set_outline_color(vertex_count_ + 3, outline_color_);
757 }
758
759 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
760 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
761 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
762 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
763 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
764 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
765 vertex_count_ += 4;
766 index_count_ += 6;
767 buffers_dirty_ = true;
768
769
770 if(style_flags_ & style_foreground && foreground_color_ & 0xff000000)
771 {
772 float x0 = pen_x_ - kerning;
773 float y0 = pen_y_;
774 float x1 = x0 + glyph->advance_x;
775 float y1 = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
776
777 atlas->packUV(whiteGlyph.region_index,
778 (uint8_t*)vertex_buffer_.data(),
779 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
780 sizeof(text_vertex));
781
782 set_vertex(vertex_count_ + 0, x0, y0, foreground_color_, style_foreground);
783 set_vertex(vertex_count_ + 1, x0, y1, foreground_color_, style_foreground);
784 set_vertex(vertex_count_ + 2, x1, y1, foreground_color_, style_foreground);
785 set_vertex(vertex_count_ + 3, x1, y0, foreground_color_, style_foreground);
786
787 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
788 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
789 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
790 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
791 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
792 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
793 vertex_count_ += 4;
794 index_count_ += 6;
795 buffers_dirty_ = true;
796
797 }
798
799 if(style_flags_ & style_strike_through && strike_through_color_ & 0xFF000000)
800 {
801 float x0 = pen_x_ - kerning;
802 float y0 = pen_y_ + 0.666667f * font.ascender;
803 float x1 = x0 + glyph->advance_x;
804 float y1 = y0 + font.underline_thickness;
805
806 atlas->packUV(whiteGlyph.region_index,
807 (uint8_t*)vertex_buffer_.data(),
808 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
809 sizeof(text_vertex));
810
811 set_vertex(vertex_count_ + 0, x0, y0, strike_through_color_, style_strike_through);
812 set_vertex(vertex_count_ + 1, x0, y1, strike_through_color_, style_strike_through);
813 set_vertex(vertex_count_ + 2, x1, y1, strike_through_color_, style_strike_through);
814 set_vertex(vertex_count_ + 3, x1, y0, strike_through_color_, style_strike_through);
815
816 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
817 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
818 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
819 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
820 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
821 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
822 vertex_count_ += 4;
823 index_count_ += 6;
824 buffers_dirty_ = true;
825
826 }
827
828 pen_x_ += glyph->advance_x;
829
830 float line_width = pen_x_ - origin_x_;
831 if(line_width > rectangle_.width)
832 {
833 rectangle_.width = line_width;
834 }
835
836 float line_height = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
837 if(line_height > rectangle_.height)
838 {
839 rectangle_.height = line_height;
840 }
841
842 previous_code_point_ = codepoint;
843}
844
845void text_buffer::vertical_center_last_line(float dy, float top, float bottom)
846{
847 for(uint32_t ii = line_start_index_; ii < vertex_count_; ii += 4)
848 {
849 if(style_buffer_[ii] == style_background)
850 {
851 vertex_buffer_[ii + 0].y = top;
852 vertex_buffer_[ii + 1].y = bottom;
853 vertex_buffer_[ii + 2].y = bottom;
854 vertex_buffer_[ii + 3].y = top;
855 }
856 else
857 {
858 vertex_buffer_[ii + 0].y += dy;
859 vertex_buffer_[ii + 1].y += dy;
860 vertex_buffer_[ii + 2].y += dy;
861 vertex_buffer_[ii + 3].y += dy;
862 }
863 }
864}
865
867{
868 bgfx::RendererType::Enum type = bgfx::getRendererType();
869
870 basic_program_ = bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_basic"),
871 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_basic"),
872 true);
873
874 distance_program_ =
875 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field"),
876 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field"),
877 true);
878
879 distance_subpixel_program_ =
880 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_subpixel"),
881 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_subpixel"),
882 true);
883
884 distance_drop_shadow_program_ =
885 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_drop_shadow"),
886 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_drop_shadow"),
887 true);
888
889 distance_drop_shadow_image_program_ = bgfx::createProgram(
890 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_drop_shadow_image"),
891 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_drop_shadow_image"),
892 true);
893
894 distance_outline_program_ =
895 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline"),
896 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline"),
897 true);
898
899 distance_outline_image_program_ = bgfx::createProgram(
900 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline_image"),
901 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline_image"),
902 true);
903
904 distance_outline_drop_shadow_image_program_ = bgfx::createProgram(
905 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline_drop_shadow_image"),
906 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline_drop_shadow_image"),
907 true);
908
909 vertex_layout_.begin()
910 .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
911 .add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true)
912 .add(bgfx::Attrib::TexCoord1, 4, bgfx::AttribType::Int16, true)
913 .add(bgfx::Attrib::TexCoord2, 4, bgfx::AttribType::Int16, true)
914 .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
915 .add(bgfx::Attrib::Color1, 4, bgfx::AttribType::Uint8, true)
916 .end();
917
918 s_tex_color_ = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
919 u_drop_shadow_color_ = bgfx::createUniform("u_dropShadowColor", bgfx::UniformType::Vec4);
920 u_params_ = bgfx::createUniform("u_params", bgfx::UniformType::Vec4);
921}
922
924{
925 BX_ASSERT(text_buffer_handles_.getNumHandles() == 0,
926 "All the text buffers must be destroyed before destroying the manager");
927 delete[] text_buffers_;
928
929 bgfx::destroy(u_params_);
930
931 bgfx::destroy(u_drop_shadow_color_);
932 bgfx::destroy(s_tex_color_);
933
934 bgfx::destroy(basic_program_);
935 bgfx::destroy(distance_program_);
936 bgfx::destroy(distance_subpixel_program_);
937 bgfx::destroy(distance_outline_program_);
938 bgfx::destroy(distance_outline_image_program_);
939 bgfx::destroy(distance_drop_shadow_program_);
940 bgfx::destroy(distance_drop_shadow_image_program_);
941 bgfx::destroy(distance_outline_drop_shadow_image_program_);
942}
943
944auto text_buffer_manager::create_text_buffer(uint32_t type, buffer_type::Enum btype) -> text_buffer_handle
945{
946 uint16_t text_idx = text_buffer_handles_.alloc();
947 buffer_cache& bc = text_buffers_[text_idx];
948
949 bc.buffer = new text_buffer(font_manager_);
950 bc.font_type = type;
951 bc.type = btype;
952 bc.index_buffer_handle_idx = bgfx::kInvalidHandle;
953 bc.vertex_buffer_handle_idx = bgfx::kInvalidHandle;
954
955 text_buffer_handle ret = {text_idx};
956 return ret;
957}
958
960{
961 BX_ASSERT(isValid(handle), "Invalid handle used");
962
963 buffer_cache& bc = text_buffers_[handle.idx];
964 text_buffer_handles_.free(handle.idx);
965 delete bc.buffer;
966 bc.buffer = nullptr;
967
968 if(bc.vertex_buffer_handle_idx == bgfx::kInvalidHandle)
969 {
970 return;
971 }
972
973 switch(bc.type)
974 {
976 {
977 bgfx::IndexBufferHandle ibh;
978 bgfx::VertexBufferHandle vbh;
979 ibh.idx = bc.index_buffer_handle_idx;
980 vbh.idx = bc.vertex_buffer_handle_idx;
981 bgfx::destroy(ibh);
982 bgfx::destroy(vbh);
983 }
984
985 break;
986
988 bgfx::DynamicIndexBufferHandle ibh;
989 bgfx::DynamicVertexBufferHandle vbh;
990 ibh.idx = bc.index_buffer_handle_idx;
991 vbh.idx = bc.vertex_buffer_handle_idx;
992 bgfx::destroy(ibh);
993 bgfx::destroy(vbh);
994
995 break;
996
997 case buffer_type::Transient: // destroyed every frame
998 break;
999 }
1000}
1001
1003 font_handle fhandle,
1004 bgfx::ViewId id,
1005 uint64_t state,
1006 int32_t depth)
1007{
1008 BX_ASSERT(isValid(handle), "Invalid handle used");
1009
1010 buffer_cache& bc = text_buffers_[handle.idx];
1011
1012 uint32_t index_size = bc.buffer->get_index_count() * bc.buffer->get_index_size();
1013 uint32_t vertex_size = bc.buffer->get_vertex_count() * bc.buffer->get_vertex_size();
1014
1015 if(0 == index_size || 0 == vertex_size)
1016 {
1017 return;
1018 }
1019
1020 bgfx::setTexture(0, s_tex_color_, font_manager_->get_atlas(fhandle)->getTextureHandle());
1021
1022 bgfx::ProgramHandle program = BGFX_INVALID_HANDLE;
1023 switch(bc.font_type)
1024 {
1025 case FONT_TYPE_ALPHA:
1026 program = basic_program_;
1027 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1028 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1029 break;
1030
1031 case FONT_TYPE_DISTANCE:
1032 {
1033 program = distance_program_;
1034 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1035 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1036
1037 float params[4] = {0.0f, (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f, 0.0f, 0.0f};
1038 bgfx::setUniform(u_params_, &params);
1039 break;
1040 }
1041
1043 program = distance_subpixel_program_;
1044 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1045 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR),
1046 bc.buffer->get_text_color());
1047 break;
1048
1050 {
1051 program = distance_outline_program_;
1052 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1053 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1054
1055 float params[4] = {0.0f,
1056 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1057 0.0f,
1058 bc.buffer->get_outline_width()};
1059 bgfx::setUniform(u_params_, &params);
1060 break;
1061 }
1062
1064 {
1065 program = distance_outline_image_program_;
1066 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1067 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1068
1069 float params[4] = {0.0f,
1070 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1071 0.0f,
1072 bc.buffer->get_outline_width()};
1073 bgfx::setUniform(u_params_, &params);
1074 break;
1075 }
1076
1078 {
1079 program = distance_drop_shadow_program_;
1080 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1081 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1082
1083 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1084 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1085 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1086 (drop_shadow_color & 0xff) / 255.0f,
1087 (drop_shadow_color >> 24) / 255.0f};
1088 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1089
1090 float params[4] = {0.0f,
1091 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1092 bc.buffer->get_drop_shadow_softener(),
1093 0.0};
1094 bgfx::setUniform(u_params_, &params);
1095 break;
1096 }
1097
1099 {
1100 program = distance_drop_shadow_image_program_;
1101 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1102 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1103
1104 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1105 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1106 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1107 (drop_shadow_color & 0xff) / 255.0f,
1108 (drop_shadow_color >> 24) / 255.0f};
1109 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1110
1111 float params[4] = {0.0f,
1112 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1113 bc.buffer->get_drop_shadow_softener(),
1114 0.0};
1115 bgfx::setUniform(u_params_, &params);
1116 break;
1117 }
1118
1120 {
1121 program = distance_outline_drop_shadow_image_program_;
1122 bgfx::setState(state | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_RGB |
1123 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1124
1125 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1126 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1127 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1128 (drop_shadow_color & 0xff) / 255.0f,
1129 (drop_shadow_color >> 24) / 255.0f};
1130 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1131
1132 float params[4] = {0.0f,
1133 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1134 bc.buffer->get_drop_shadow_softener(),
1135 bc.buffer->get_outline_width()};
1136 bgfx::setUniform(u_params_, &params);
1137 break;
1138 }
1139
1140 default:
1141 break;
1142 }
1143
1144 switch(bc.type)
1145 {
1147 {
1148 bgfx::IndexBufferHandle ibh;
1149 bgfx::VertexBufferHandle vbh;
1150
1151 if(bgfx::kInvalidHandle == bc.vertex_buffer_handle_idx)
1152 {
1153 ibh = bgfx::createIndexBuffer(bgfx::copy(bc.buffer->get_index_buffer(), index_size));
1154
1155 vbh = bgfx::createVertexBuffer(bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size), vertex_layout_);
1156
1157 bc.vertex_buffer_handle_idx = vbh.idx;
1158 bc.index_buffer_handle_idx = ibh.idx;
1159 }
1160 else
1161 {
1162 vbh.idx = bc.vertex_buffer_handle_idx;
1163 ibh.idx = bc.index_buffer_handle_idx;
1164 }
1165
1166 bgfx::setVertexBuffer(0, vbh, 0, bc.buffer->get_vertex_count());
1167 bgfx::setIndexBuffer(ibh, 0, bc.buffer->get_index_count());
1168 }
1169 break;
1170
1172 {
1173 bgfx::DynamicIndexBufferHandle ibh;
1174 bgfx::DynamicVertexBufferHandle vbh;
1175
1176 if(bgfx::kInvalidHandle == bc.vertex_buffer_handle_idx)
1177 {
1178 ibh = bgfx::createDynamicIndexBuffer(bgfx::copy(bc.buffer->get_index_buffer(), index_size),
1179 BGFX_BUFFER_ALLOW_RESIZE);
1180
1181 vbh = bgfx::createDynamicVertexBuffer(bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size),
1182 vertex_layout_,
1183 BGFX_BUFFER_ALLOW_RESIZE);
1184
1185 bc.index_buffer_handle_idx = ibh.idx;
1186 bc.vertex_buffer_handle_idx = vbh.idx;
1187 }
1188 else if(bc.buffer->get_buffers_dirty())
1189 {
1190 ibh.idx = bc.index_buffer_handle_idx;
1191 vbh.idx = bc.vertex_buffer_handle_idx;
1192
1193 bgfx::update(ibh, 0, bgfx::copy(bc.buffer->get_index_buffer(), index_size));
1194
1195 bgfx::update(vbh, 0, bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size));
1196 }
1197
1198 ibh.idx = bc.index_buffer_handle_idx;
1199 vbh.idx = bc.vertex_buffer_handle_idx;
1200
1201 bgfx::setVertexBuffer(0, vbh, 0, bc.buffer->get_vertex_count());
1202 bgfx::setIndexBuffer(ibh, 0, bc.buffer->get_index_count());
1203 }
1204 break;
1205
1207 {
1208 bgfx::TransientIndexBuffer tib;
1209 bgfx::TransientVertexBuffer tvb;
1210 bgfx::allocTransientIndexBuffer(&tib, bc.buffer->get_index_count());
1211 bgfx::allocTransientVertexBuffer(&tvb, bc.buffer->get_vertex_count(), vertex_layout_);
1212 bx::memCopy(tib.data, bc.buffer->get_index_buffer(), index_size);
1213 bx::memCopy(tvb.data, bc.buffer->get_vertex_buffer(), vertex_size);
1214 bgfx::setVertexBuffer(0, &tvb, 0, bc.buffer->get_vertex_count());
1215 bgfx::setIndexBuffer(&tib, 0, bc.buffer->get_index_count());
1216 }
1217 break;
1218 }
1219
1220 bgfx::submit(id, program, depth);
1221
1222 bc.buffer->set_buffers_dirty(false);
1223}
1224
1225void text_buffer_manager::set_style(text_buffer_handle handle, uint32_t flags)
1226{
1227 BX_ASSERT(isValid(handle), "Invalid handle used");
1228 buffer_cache& bc = text_buffers_[handle.idx];
1229 bc.buffer->set_style(flags);
1230}
1231
1232void text_buffer_manager::set_text_color(text_buffer_handle handle, uint32_t rgba)
1233{
1234 BX_ASSERT(isValid(handle), "Invalid handle used");
1235 buffer_cache& bc = text_buffers_[handle.idx];
1236 bc.buffer->set_text_color(rgba);
1237}
1238
1239void text_buffer_manager::set_background_color(text_buffer_handle handle, uint32_t rgba)
1240{
1241 BX_ASSERT(isValid(handle), "Invalid handle used");
1242 buffer_cache& bc = text_buffers_[handle.idx];
1243 bc.buffer->set_background_color(rgba);
1244}
1245
1246void text_buffer_manager::set_foreground_color(text_buffer_handle handle, uint32_t rgba)
1247{
1248 BX_ASSERT(isValid(handle), "Invalid handle used");
1249 buffer_cache& bc = text_buffers_[handle.idx];
1250 bc.buffer->set_foreground_color(rgba);
1251}
1252
1253void text_buffer_manager::set_overline_color(text_buffer_handle handle, uint32_t rgba)
1254{
1255 BX_ASSERT(isValid(handle), "Invalid handle used");
1256 buffer_cache& bc = text_buffers_[handle.idx];
1257 bc.buffer->set_overline_color(rgba);
1258}
1259
1260void text_buffer_manager::set_underline_color(text_buffer_handle handle, uint32_t rgba)
1261{
1262 BX_ASSERT(isValid(handle), "Invalid handle used");
1263 buffer_cache& bc = text_buffers_[handle.idx];
1264 bc.buffer->set_underline_color(rgba);
1265}
1266
1267void text_buffer_manager::set_strike_through_color(text_buffer_handle handle, uint32_t rgba)
1268{
1269 BX_ASSERT(isValid(handle), "Invalid handle used");
1270 buffer_cache& bc = text_buffers_[handle.idx];
1271 bc.buffer->set_strike_through_color(rgba);
1272}
1273
1274void text_buffer_manager::set_outline_color(text_buffer_handle handle, uint32_t rgba)
1275{
1276 BX_ASSERT(isValid(handle), "Invalid handle used");
1277 buffer_cache& bc = text_buffers_[handle.idx];
1278 bc.buffer->set_outline_color(rgba);
1279}
1280
1281void text_buffer_manager::set_outline_width(text_buffer_handle handle, float outline_width)
1282{
1283 BX_ASSERT(isValid(handle), "Invalid handle used");
1284 buffer_cache& bc = text_buffers_[handle.idx];
1285 bc.buffer->set_outline_width(outline_width);
1286}
1287
1288void text_buffer_manager::set_drop_shadow_color(text_buffer_handle handle, uint32_t rgba)
1289{
1290 BX_ASSERT(isValid(handle), "Invalid handle used");
1291 buffer_cache& bc = text_buffers_[handle.idx];
1292 bc.buffer->set_drop_shadow_color(rgba);
1293}
1294
1295void text_buffer_manager::set_drop_shadow_offset(text_buffer_handle handle, float u, float v)
1296{
1297 BX_ASSERT(isValid(handle), "Invalid handle used");
1298 buffer_cache& bc = text_buffers_[handle.idx];
1299 bc.buffer->set_drop_shadow_offset(u, v);
1300}
1301
1302void text_buffer_manager::set_drop_shadow_softener(text_buffer_handle handle, float smoother)
1303{
1304 BX_ASSERT(isValid(handle), "Invalid handle used");
1305 buffer_cache& bc = text_buffers_[handle.idx];
1306 bc.buffer->set_drop_shadow_softener(smoother);
1307}
1308
1309void text_buffer_manager::set_pen_position(text_buffer_handle handle, float x, float y)
1310{
1311 BX_ASSERT(isValid(handle), "Invalid handle used");
1312 buffer_cache& bc = text_buffers_[handle.idx];
1313 bc.buffer->set_pen_position(x, y);
1314}
1315
1316void text_buffer_manager::set_pen_origin(text_buffer_handle handle, float x, float y)
1317{
1318 BX_ASSERT(isValid(handle), "Invalid handle used");
1319 buffer_cache& bc = text_buffers_[handle.idx];
1320 bc.buffer->set_pen_origin(x, y);
1321}
1322
1323void text_buffer_manager::get_pen_position(text_buffer_handle handle, float* x, float* y)
1324{
1325 BX_ASSERT(isValid(handle), "Invalid handle used");
1326 buffer_cache& bc = text_buffers_[handle.idx];
1327 bc.buffer->get_pen_position(x, y);
1328}
1329
1330void text_buffer_manager::set_apply_kerning(text_buffer_handle handle, bool apply_kerning)
1331{
1332 BX_ASSERT(isValid(handle), "Invalid handle used");
1333 buffer_cache& bc = text_buffers_[handle.idx];
1334 bc.buffer->set_apply_kerning(apply_kerning);
1335}
1336
1338 font_handle fhandle,
1339 const char* _string,
1340 const char* _end)
1341{
1342 BX_ASSERT(isValid(handle), "Invalid handle used");
1343 buffer_cache& bc = text_buffers_[handle.idx];
1344 bc.buffer->append_text(fhandle, _string, _end);
1345}
1346
1348 font_handle fhandle,
1349 const wchar_t* _string,
1350 const wchar_t* _end)
1351{
1352 BX_ASSERT(isValid(handle), "Invalid handle used");
1353 buffer_cache& bc = text_buffers_[handle.idx];
1354 bc.buffer->append_text(fhandle, _string, _end);
1355}
1356
1357void text_buffer_manager::append_atlas_face(text_buffer_handle handle, font_handle fhandle, uint16_t _faceIndex)
1358{
1359 BX_ASSERT(isValid(handle), "Invalid handle used");
1360 buffer_cache& bc = text_buffers_[handle.idx];
1361 bc.buffer->append_atlas_face(fhandle, _faceIndex);
1362}
1363
1365{
1366 BX_ASSERT(isValid(handle), "Invalid handle used");
1367 buffer_cache& bc = text_buffers_[handle.idx];
1368 bc.buffer->clear_text_buffer();
1369}
1370
1372{
1373 BX_ASSERT(isValid(handle), "Invalid handle used");
1374 buffer_cache& bc = text_buffers_[handle.idx];
1375 return bc.buffer->get_rectangle();
1376}
1377
1378} // namespace gfx
manifold_type type
void packFaceLayerUV(uint32_t _idx, uint8_t *_vertexBuffer, uint32_t _offset, uint32_t _stride) const
Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atl...
uint16_t getTextureSize() const
retrieve the size of side of a texture in pixels
Definition cube_atlas.h:118
auto get_glyph_info(font_handle handle, code_point code_point) -> const glyph_info *
auto get_white_glyph(font_handle handle) const -> const glyph_info &
auto get_atlas(font_handle handle) const -> Atlas *
Retrieve the atlas used by the font manager (e.g. to add stuff to it)
auto get_kerning(font_handle handle, code_point prev_code_point, code_point code_point) -> float
auto get_font_info(font_handle handle) const -> const font_info &
void set_pen_origin(text_buffer_handle handle, float x, float y)
void set_foreground_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void destroy_text_buffer(text_buffer_handle handle)
void set_strike_through_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void set_drop_shadow_softener(text_buffer_handle handle, float smoother=1.0f)
auto create_text_buffer(uint32_t type, buffer_type::Enum btype) -> text_buffer_handle
void set_style(text_buffer_handle handle, uint32_t flags=style_normal)
void clear_text_buffer(text_buffer_handle handle)
Clear the text buffer and reset its state (pen/color).
void set_outline_width(text_buffer_handle handle, float outline_width=3.0f)
void set_drop_shadow_offset(text_buffer_handle handle, float u, float v)
text_buffer_manager(font_manager *font_manager)
void submit_text_buffer(text_buffer_handle handle, font_handle fhandle, bgfx::ViewId id, uint64_t state=0, int32_t depth=0)
void set_drop_shadow_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void set_apply_kerning(text_buffer_handle handle, bool apply_kerning)
void set_text_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void set_background_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void append_text(text_buffer_handle handle, font_handle fhandle, const char *string, const char *end=nullptr)
Append an ASCII/utf-8 string to the buffer using current pen position and color.
void get_pen_position(text_buffer_handle handle, float *x, float *y)
void set_pen_position(text_buffer_handle handle, float x, float y)
void set_underline_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void set_outline_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
void set_overline_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
auto get_rectangle(text_buffer_handle handle) const -> text_rectangle
Return the rectangular size of the current text buffer (including all its content).
void append_atlas_face(text_buffer_handle handle, font_handle fhandle, uint16_t face_index)
Append a whole face of the atlas cube, mostly used for debugging and visualizing atlas.
void set_pen_origin(float x, float y)
auto get_drop_shadow_offset_v() -> float
auto get_index_buffer() const -> const uint16_t *
auto get_index_count() const -> uint32_t
auto get_drop_shadow_offset_u() -> float
auto get_drop_shadow_color() -> uint32_t
void set_drop_shadow_color(uint32_t rgba=0xff000000)
auto get_vertex_buffer() -> const uint8_t *
void set_text_color(uint32_t rgba=0xff000000)
void resize_buffers(size_t max_buffered_characters)
auto get_vertex_size() const -> uint32_t
void set_drop_shadow_softener(float smoother)
auto get_outline_color() -> uint32_t
void append_text(font_handle font_handle, const char *str, const char *end=nullptr)
void set_overline_color(uint32_t rgba=0xff000000)
auto get_drop_shadow_softener() -> float
auto get_vertex_count() const -> uint32_t
void set_buffers_dirty(bool dirty)
void get_pen_position(float *x, float *y)
auto get_text_color() const -> uint32_t
auto get_max_buffered_characters() const -> size_t
void set_strike_through_color(uint32_t rgba=0xff000000)
auto get_rectangle() const -> text_rectangle
void set_drop_shadow_offset(float u, float v)
text_buffer(font_manager *manager)
void set_pen_position(float x, float y)
auto get_index_size() const -> uint32_t
void append_atlas_face(font_handle font_handle, uint16_t face_index)
void set_foreground_color(uint32_t rgba=0xff000000)
void set_underline_color(uint32_t rgba=0xff000000)
auto get_outline_width() -> float
void set_outline_color(uint32_t rgba=0xff000000)
auto get_buffers_dirty() const -> bool
void set_outline_width(float outline_width=3.0f)
void set_apply_kerning(bool apply_kerning)
void set_background_color(uint32_t rgba=0xff000000)
void set_style(uint32_t flags=style_normal)
#define FONT_TYPE_DISTANCE_OUTLINE_DROP_SHADOW_IMAGE
#define FONT_TYPE_ALPHA
#define FONT_TYPE_DISTANCE_DROP_SHADOW
#define FONT_TYPE_DISTANCE_OUTLINE_IMAGE
#define FONT_TYPE_DISTANCE
#define FONT_TYPE_DISTANCE_DROP_SHADOW_IMAGE
#define FONT_TYPE_DISTANCE_OUTLINE
#define FONT_TYPE_DISTANCE_SUBPIXEL
#define FONT_TYPE_MASK_DISTANCE_DROP_SHADOW
#define UTF8_ACCEPT
Definition utf8.h:9
ImGui::Font::Enum font
Definition hub.cpp:24
uint32_t code_point
Unicode value of a character.
@ style_strike_through
void end(encoder *_encoder)
Definition graphics.cpp:270
float y
float x
gfx::uniform_handle handle
Definition uniform.cpp:9
uint32_t utf8_decode(uint32_t *_state, uint32_t *_codep, uint8_t _ch)
Definition utf8.cpp:46
bool isValid(SpriteHandle _handle)
Definition debugdraw.h:34