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(21 - 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 auto dif = (vertex_count_ / 4) - get_max_buffered_characters();
436 //background
437 size_t max_quads_per_glyph = 1;
438 size_t capacity_growth = bx::min<size_t>(10, dif);
439 resize_buffers(get_max_buffered_characters() + max_quads_per_glyph * capacity_growth);
440 }
441
442 const Atlas* atlas = font_manager_->get_atlas(handle);
443
444 float x0 = pen_x_;
445 float y0 = pen_y_;
446 float x1 = x0 + (float)atlas->getTextureSize();
447 float y1 = y0 + (float)atlas->getTextureSize();
448
449 atlas->packFaceLayerUV(face_index,
450 (uint8_t*)vertex_buffer_.data(),
451 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
452 sizeof(text_vertex));
453
454 set_vertex(vertex_count_ + 0, x0, y0, background_color_);
455 set_vertex(vertex_count_ + 1, x0, y1, background_color_);
456 set_vertex(vertex_count_ + 2, x1, y1, background_color_);
457 set_vertex(vertex_count_ + 3, x1, y0, background_color_);
458
459 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
460 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
461 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
462 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
463 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
464 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
465 vertex_count_ += 4;
466 index_count_ += 6;
467 buffers_dirty_ = true;
468
469 pen_x_ += x1 - x0;
470}
471
473{
474 pen_x_ = 0;
475 pen_y_ = 0;
476 origin_x_ = 0;
477 origin_y_ = 0;
478
479 vertex_count_ = 0;
480 index_count_ = 0;
481 line_start_index_ = 0;
482 line_ascender_ = 0;
483 line_descender_ = 0;
484 line_gap_ = 0;
485 previous_code_point_ = 0;
486 rectangle_.width = 0;
487 rectangle_.height = 0;
488}
489
490void text_buffer::append_glyph(font_handle handle, code_point codepoint, bool shadow)
491{
492 if(codepoint == L'\t')
493 {
494 for(uint32_t ii = 0; ii < 4; ++ii)
495 {
496 append_glyph(handle, L' ', shadow);
497 }
498 return;
499 }
500
501 const glyph_info* glyph = font_manager_->get_glyph_info(handle, codepoint);
502 BX_WARN(NULL != glyph, "Glyph not found (font handle %d, code point %d)", handle.idx, codepoint);
503 if(nullptr == glyph)
504 {
505 previous_code_point_ = 0;
506 return;
507 }
508
509 if(vertex_count_ / 4 >= get_max_buffered_characters())
510 {
511 // background, shadow, underline, overline, glyph, foreground
512 size_t max_quads_per_glyph = 6;
513 auto dif = (vertex_count_ / 4) - get_max_buffered_characters();
514 size_t capacity_growth = bx::min<size_t>(10, dif);
515 resize_buffers(get_max_buffered_characters() + max_quads_per_glyph * capacity_growth);
516 }
517
518 const font_info& font = font_manager_->get_font_info(handle);
519
520 if(codepoint == L'\n')
521 {
522 line_gap_ = font.line_gap;
523 line_descender_ = font.descender;
524 line_ascender_ = font.ascender;
525 line_start_index_ = vertex_count_;
526 previous_code_point_ = 0;
527 pen_x_ = origin_x_;
528 pen_y_ += line_gap_ + line_ascender_ - line_descender_;
529 return;
530 }
531
532 // is there a change of font size that require the text on the left to be centered again ?
533 if(font.ascender > line_ascender_ || (font.descender < line_descender_))
534 {
535 if(font.descender < line_descender_)
536 {
537 line_descender_ = font.descender;
538 line_gap_ = font.line_gap;
539 }
540
541 float txtDecals = (font.ascender - line_ascender_);
542 line_ascender_ = font.ascender;
543 line_gap_ = font.line_gap;
544 vertical_center_last_line((txtDecals),
545 (pen_y_ - line_ascender_),
546 (pen_y_ + line_ascender_ - line_descender_ + line_gap_));
547 }
548
549 float kerning = 0.0f;
550 if(apply_kerning_)
551 {
552 kerning = font_manager_->get_kerning(handle, previous_code_point_, codepoint);
553 pen_x_ += kerning;
554 }
555
556 const glyph_info& whiteGlyph = font_manager_->get_white_glyph(handle);
557 const Atlas* atlas = font_manager_->get_atlas(handle);
558 const AtlasRegion& atlasRegion = atlas->getRegion(glyph->region_index);
559
560 const bool is_drop_shadow_font =
561 (font_manager_->get_font_info(handle).font_type & FONT_TYPE_MASK_DISTANCE_DROP_SHADOW) != 0;
562
563 if((shadow || !is_drop_shadow_font) && style_flags_ & style_background && background_color_ & 0xff000000)
564 {
565 float x0 = pen_x_ - kerning;
566 float y0 = pen_y_;
567 float x1 = x0 + glyph->advance_x;
568 float y1 = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
569
570 atlas->packUV(whiteGlyph.region_index,
571 (uint8_t*)vertex_buffer_.data(),
572 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
573 sizeof(text_vertex));
574
575 set_vertex(vertex_count_ + 0, x0, y0, background_color_, style_background);
576 set_vertex(vertex_count_ + 1, x0, y1, background_color_, style_background);
577 set_vertex(vertex_count_ + 2, x1, y1, background_color_, style_background);
578 set_vertex(vertex_count_ + 3, x1, y0, background_color_, style_background);
579
580 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
581 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
582 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
583 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
584 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
585 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
586 vertex_count_ += 4;
587 index_count_ += 6;
588 buffers_dirty_ = true;
589
590 }
591
592 if(shadow)
593 {
594 if(atlasRegion.getType() != AtlasRegion::TYPE_BGRA8)
595 {
596 float extra_x_offset = drop_shadow_offset_[0] * font.scale;
597 float extra_y_offset = drop_shadow_offset_[1] * font.scale;
598
599 uint32_t adjusted_drop_shadow_color =
600 ((((drop_shadow_color_ & 0xff000000) >> 8) * (text_color_ >> 24)) & 0xff000000) |
601 (drop_shadow_color_ & 0x00ffffff);
602
603 const uint8_t shadowA = (drop_shadow_color_ >> 24) & 0xFF;
604
605 if(shadowA > 0 || std::fabs(extra_x_offset) > 1e-6f || std::fabs(extra_y_offset) > 1e-6f)
606 {
607 float x0 = pen_x_ + glyph->offset_x + extra_x_offset;
608 float y0 = pen_y_ + line_ascender_ + glyph->offset_y + extra_y_offset;
609 float x1 = x0 + glyph->width;
610 float y1 = y0 + glyph->height;
611
612 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
613
614 atlas->packUV(glyph->region_index,
615 (uint8_t*)vertex_buffer_.data(),
616 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u2),
617 sizeof(text_vertex));
618
619 set_vertex(vertex_count_ + 0, x0, y0, adjusted_drop_shadow_color);
620 set_vertex(vertex_count_ + 1, x0, y1, adjusted_drop_shadow_color);
621 set_vertex(vertex_count_ + 2, x1, y1, adjusted_drop_shadow_color);
622 set_vertex(vertex_count_ + 3, x1, y0, adjusted_drop_shadow_color);
623
624 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
625 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
626 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
627 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
628 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
629 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
630 vertex_count_ += 4;
631 index_count_ += 6;
632 buffers_dirty_ = true;
633
634 }
635 }
636
637 pen_x_ += glyph->advance_x;
638
639 float lineWidth = pen_x_ - origin_x_;
640 if(lineWidth > rectangle_.width)
641 {
642 rectangle_.width = lineWidth;
643 }
644
645 float lineHeight = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
646 if(lineHeight > rectangle_.height)
647 {
648 rectangle_.height = lineHeight;
649 }
650
651 previous_code_point_ = codepoint;
652
653 return;
654 }
655
656 if(style_flags_ & style_underline && underline_color_ & 0xFF000000)
657 {
658 float x0 = pen_x_ - kerning;
659 float y0 = pen_y_ + line_ascender_ - line_descender_ * 0.5f;
660 float x1 = x0 + glyph->advance_x;
661 float y1 = y0 + font.underline_thickness;
662
663 atlas->packUV(whiteGlyph.region_index,
664 (uint8_t*)vertex_buffer_.data(),
665 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
666 sizeof(text_vertex));
667
668 set_vertex(vertex_count_ + 0, x0, y0, underline_color_, style_underline);
669 set_vertex(vertex_count_ + 1, x0, y1, underline_color_, style_underline);
670 set_vertex(vertex_count_ + 2, x1, y1, underline_color_, style_underline);
671 set_vertex(vertex_count_ + 3, x1, y0, underline_color_, style_underline);
672
673 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
674 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
675 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
676 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
677 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
678 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
679 vertex_count_ += 4;
680 index_count_ += 6;
681 buffers_dirty_ = true;
682
683 }
684
685 if(style_flags_ & style_overline && overline_color_ & 0xFF000000)
686 {
687 float x0 = pen_x_ - kerning;
688 float y0 = pen_y_;
689 float x1 = x0 + glyph->advance_x;
690 float y1 = y0 + font.underline_thickness;
691
692 atlas->packUV(whiteGlyph.region_index,
693 (uint8_t*)vertex_buffer_.data(),
694 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
695 sizeof(text_vertex));
696
697 set_vertex(vertex_count_ + 0, x0, y0, overline_color_, style_overline);
698 set_vertex(vertex_count_ + 1, x0, y1, overline_color_, style_overline);
699 set_vertex(vertex_count_ + 2, x1, y1, overline_color_, style_overline);
700 set_vertex(vertex_count_ + 3, x1, y0, overline_color_, style_overline);
701
702 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
703 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
704 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
705 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
706 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
707 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
708 vertex_count_ += 4;
709 index_count_ += 6;
710 buffers_dirty_ = true;
711
712 }
713
714 if(!shadow && atlasRegion.getType() == AtlasRegion::TYPE_BGRA8)
715 {
716 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
717
718 atlas->packUV(glyph->region_index,
719 (uint8_t*)vertex_buffer_.data(),
720 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u1),
721 sizeof(text_vertex));
722
723 float glyph_scale = glyph->bitmap_scale;
724 float glyph_width = glyph->width * glyph_scale;
725 float glyph_height = glyph->height * glyph_scale;
726 float x0 = pen_x_ + glyph->offset_x;
727 float y0 = pen_y_ + (font.ascender + -font.descender - glyph_height) / 2;
728 float x1 = x0 + glyph_width;
729 float y1 = y0 + glyph_height;
730
731 set_vertex(vertex_count_ + 0, x0, y0, text_color_);
732 set_vertex(vertex_count_ + 1, x0, y1, text_color_);
733 set_vertex(vertex_count_ + 2, x1, y1, text_color_);
734 set_vertex(vertex_count_ + 3, x1, y0, text_color_);
735 }
736 else if(!shadow)
737 {
738 bx::memSet(&vertex_buffer_[vertex_count_], 0, sizeof(text_vertex) * 4);
739
740 atlas->packUV(glyph->region_index,
741 (uint8_t*)vertex_buffer_.data(),
742 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
743 sizeof(text_vertex));
744
745 float x0 = pen_x_ + glyph->offset_x;
746 float y0 = pen_y_ + line_ascender_ + glyph->offset_y;
747 float x1 = x0 + glyph->width;
748 float y1 = y0 + glyph->height;
749
750 set_vertex(vertex_count_ + 0, x0, y0, text_color_);
751 set_vertex(vertex_count_ + 1, x0, y1, text_color_);
752 set_vertex(vertex_count_ + 2, x1, y1, text_color_);
753 set_vertex(vertex_count_ + 3, x1, y0, text_color_);
754
755 set_outline_color(vertex_count_ + 0, outline_color_);
756 set_outline_color(vertex_count_ + 1, outline_color_);
757 set_outline_color(vertex_count_ + 2, outline_color_);
758 set_outline_color(vertex_count_ + 3, outline_color_);
759 }
760
761 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
762 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
763 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
764 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
765 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
766 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
767 vertex_count_ += 4;
768 index_count_ += 6;
769 buffers_dirty_ = true;
770
771
772 if(style_flags_ & style_foreground && foreground_color_ & 0xff000000)
773 {
774 float x0 = pen_x_ - kerning;
775 float y0 = pen_y_;
776 float x1 = x0 + glyph->advance_x;
777 float y1 = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
778
779 atlas->packUV(whiteGlyph.region_index,
780 (uint8_t*)vertex_buffer_.data(),
781 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
782 sizeof(text_vertex));
783
784 set_vertex(vertex_count_ + 0, x0, y0, foreground_color_, style_foreground);
785 set_vertex(vertex_count_ + 1, x0, y1, foreground_color_, style_foreground);
786 set_vertex(vertex_count_ + 2, x1, y1, foreground_color_, style_foreground);
787 set_vertex(vertex_count_ + 3, x1, y0, foreground_color_, style_foreground);
788
789 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
790 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
791 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
792 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
793 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
794 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
795 vertex_count_ += 4;
796 index_count_ += 6;
797 buffers_dirty_ = true;
798
799 }
800
801 if(style_flags_ & style_strike_through && strike_through_color_ & 0xFF000000)
802 {
803 float x0 = pen_x_ - kerning;
804 float y0 = pen_y_ + 0.666667f * font.ascender;
805 float x1 = x0 + glyph->advance_x;
806 float y1 = y0 + font.underline_thickness;
807
808 atlas->packUV(whiteGlyph.region_index,
809 (uint8_t*)vertex_buffer_.data(),
810 sizeof(text_vertex) * vertex_count_ + offsetof(text_vertex, u),
811 sizeof(text_vertex));
812
813 set_vertex(vertex_count_ + 0, x0, y0, strike_through_color_, style_strike_through);
814 set_vertex(vertex_count_ + 1, x0, y1, strike_through_color_, style_strike_through);
815 set_vertex(vertex_count_ + 2, x1, y1, strike_through_color_, style_strike_through);
816 set_vertex(vertex_count_ + 3, x1, y0, strike_through_color_, style_strike_through);
817
818 index_buffer_[index_count_ + 0] = vertex_count_ + 0;
819 index_buffer_[index_count_ + 1] = vertex_count_ + 1;
820 index_buffer_[index_count_ + 2] = vertex_count_ + 2;
821 index_buffer_[index_count_ + 3] = vertex_count_ + 0;
822 index_buffer_[index_count_ + 4] = vertex_count_ + 2;
823 index_buffer_[index_count_ + 5] = vertex_count_ + 3;
824 vertex_count_ += 4;
825 index_count_ += 6;
826 buffers_dirty_ = true;
827
828 }
829
830 pen_x_ += glyph->advance_x;
831
832 float line_width = pen_x_ - origin_x_;
833 if(line_width > rectangle_.width)
834 {
835 rectangle_.width = line_width;
836 }
837
838 float line_height = pen_y_ + line_ascender_ - line_descender_ + line_gap_;
839 if(line_height > rectangle_.height)
840 {
841 rectangle_.height = line_height;
842 }
843
844 previous_code_point_ = codepoint;
845}
846
847void text_buffer::vertical_center_last_line(float dy, float top, float bottom)
848{
849 for(uint32_t ii = line_start_index_; ii < vertex_count_; ii += 4)
850 {
851 if(style_buffer_[ii] == style_background)
852 {
853 vertex_buffer_[ii + 0].y = top;
854 vertex_buffer_[ii + 1].y = bottom;
855 vertex_buffer_[ii + 2].y = bottom;
856 vertex_buffer_[ii + 3].y = top;
857 }
858 else
859 {
860 vertex_buffer_[ii + 0].y += dy;
861 vertex_buffer_[ii + 1].y += dy;
862 vertex_buffer_[ii + 2].y += dy;
863 vertex_buffer_[ii + 3].y += dy;
864 }
865 }
866}
867
869{
870 bgfx::RendererType::Enum type = bgfx::getRendererType();
871
872 basic_program_ = bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_basic"),
873 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_basic"),
874 true);
875
876 distance_program_ =
877 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field"),
878 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field"),
879 true);
880
881 distance_subpixel_program_ =
882 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_subpixel"),
883 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_subpixel"),
884 true);
885
886 distance_drop_shadow_program_ =
887 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_drop_shadow"),
888 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_drop_shadow"),
889 true);
890
891 distance_drop_shadow_image_program_ = bgfx::createProgram(
892 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_drop_shadow_image"),
893 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_drop_shadow_image"),
894 true);
895
896 distance_outline_program_ =
897 bgfx::createProgram(bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline"),
898 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline"),
899 true);
900
901 distance_outline_image_program_ = bgfx::createProgram(
902 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline_image"),
903 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline_image"),
904 true);
905
906 distance_outline_drop_shadow_image_program_ = bgfx::createProgram(
907 bgfx::createEmbeddedShader(s_embedded_shaders, type, "vs_font_distance_field_outline_drop_shadow_image"),
908 bgfx::createEmbeddedShader(s_embedded_shaders, type, "fs_font_distance_field_outline_drop_shadow_image"),
909 true);
910
911 vertex_layout_.begin()
912 .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
913 .add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true)
914 .add(bgfx::Attrib::TexCoord1, 4, bgfx::AttribType::Int16, true)
915 .add(bgfx::Attrib::TexCoord2, 4, bgfx::AttribType::Int16, true)
916 .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
917 .add(bgfx::Attrib::Color1, 4, bgfx::AttribType::Uint8, true)
918 .end();
919
920 s_tex_color_ = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
921 u_drop_shadow_color_ = bgfx::createUniform("u_dropShadowColor", bgfx::UniformType::Vec4);
922 u_params_ = bgfx::createUniform("u_params", bgfx::UniformType::Vec4);
923}
924
926{
927 BX_ASSERT(text_buffer_handles_.getNumHandles() == 0,
928 "All the text buffers must be destroyed before destroying the manager");
929 delete[] text_buffers_;
930
931 bgfx::destroy(u_params_);
932
933 bgfx::destroy(u_drop_shadow_color_);
934 bgfx::destroy(s_tex_color_);
935
936 bgfx::destroy(basic_program_);
937 bgfx::destroy(distance_program_);
938 bgfx::destroy(distance_subpixel_program_);
939 bgfx::destroy(distance_outline_program_);
940 bgfx::destroy(distance_outline_image_program_);
941 bgfx::destroy(distance_drop_shadow_program_);
942 bgfx::destroy(distance_drop_shadow_image_program_);
943 bgfx::destroy(distance_outline_drop_shadow_image_program_);
944}
945
946auto text_buffer_manager::create_text_buffer(uint32_t type, buffer_type::Enum btype) -> text_buffer_handle
947{
948 uint16_t text_idx = text_buffer_handles_.alloc();
949 buffer_cache& bc = text_buffers_[text_idx];
950
951 bc.buffer = new text_buffer(font_manager_);
952 bc.font_type = type;
953 bc.type = btype;
954 bc.index_buffer_handle_idx = bgfx::kInvalidHandle;
955 bc.vertex_buffer_handle_idx = bgfx::kInvalidHandle;
956
957 text_buffer_handle ret = {text_idx};
958 return ret;
959}
960
962{
963 BX_ASSERT(isValid(handle), "Invalid handle used");
964
965 buffer_cache& bc = text_buffers_[handle.idx];
966 text_buffer_handles_.free(handle.idx);
967 delete bc.buffer;
968 bc.buffer = nullptr;
969
970 if(bc.vertex_buffer_handle_idx == bgfx::kInvalidHandle)
971 {
972 return;
973 }
974
975 switch(bc.type)
976 {
978 {
979 bgfx::IndexBufferHandle ibh;
980 bgfx::VertexBufferHandle vbh;
981 ibh.idx = bc.index_buffer_handle_idx;
982 vbh.idx = bc.vertex_buffer_handle_idx;
983 bgfx::destroy(ibh);
984 bgfx::destroy(vbh);
985 }
986
987 break;
988
990 bgfx::DynamicIndexBufferHandle ibh;
991 bgfx::DynamicVertexBufferHandle vbh;
992 ibh.idx = bc.index_buffer_handle_idx;
993 vbh.idx = bc.vertex_buffer_handle_idx;
994 bgfx::destroy(ibh);
995 bgfx::destroy(vbh);
996
997 break;
998
999 case buffer_type::Transient: // destroyed every frame
1000 break;
1001 }
1002}
1003
1005 font_handle fhandle,
1006 bgfx::ViewId id,
1007 uint64_t state,
1008 int32_t depth)
1009{
1010 BX_ASSERT(isValid(handle), "Invalid handle used");
1011
1012 buffer_cache& bc = text_buffers_[handle.idx];
1013
1014 uint32_t index_size = bc.buffer->get_index_count() * bc.buffer->get_index_size();
1015 uint32_t vertex_size = bc.buffer->get_vertex_count() * bc.buffer->get_vertex_size();
1016
1017 if(0 == index_size || 0 == vertex_size)
1018 {
1019 return;
1020 }
1021
1022 bgfx::setTexture(0, s_tex_color_, font_manager_->get_atlas(fhandle)->getTextureHandle());
1023
1024 bgfx::ProgramHandle program = BGFX_INVALID_HANDLE;
1025 switch(bc.font_type)
1026 {
1027 case FONT_TYPE_ALPHA:
1028 program = basic_program_;
1029 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1030 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1031 break;
1032
1033 case FONT_TYPE_DISTANCE:
1034 {
1035 program = distance_program_;
1036 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1037 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1038
1039 float params[4] = {0.0f, (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f, 0.0f, 0.0f};
1040 bgfx::setUniform(u_params_, &params);
1041 break;
1042 }
1043
1045 program = distance_subpixel_program_;
1046 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1047 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR),
1048 bc.buffer->get_text_color());
1049 break;
1050
1052 {
1053 program = distance_outline_program_;
1054 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1055 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1056
1057 float params[4] = {0.0f,
1058 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1059 0.0f,
1060 bc.buffer->get_outline_width()};
1061 bgfx::setUniform(u_params_, &params);
1062 break;
1063 }
1064
1066 {
1067 program = distance_outline_image_program_;
1068 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1069 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1070
1071 float params[4] = {0.0f,
1072 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1073 0.0f,
1074 bc.buffer->get_outline_width()};
1075 bgfx::setUniform(u_params_, &params);
1076 break;
1077 }
1078
1080 {
1081 program = distance_drop_shadow_program_;
1082 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1083 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1084
1085 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1086 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1087 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1088 (drop_shadow_color & 0xff) / 255.0f,
1089 (drop_shadow_color >> 24) / 255.0f};
1090 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1091
1092 float params[4] = {0.0f,
1093 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1094 bc.buffer->get_drop_shadow_softener(),
1095 0.0};
1096 bgfx::setUniform(u_params_, &params);
1097 break;
1098 }
1099
1101 {
1102 program = distance_drop_shadow_image_program_;
1103 bgfx::setState(state | BGFX_STATE_WRITE_RGB |
1104 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1105
1106 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1107 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1108 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1109 (drop_shadow_color & 0xff) / 255.0f,
1110 (drop_shadow_color >> 24) / 255.0f};
1111 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1112
1113 float params[4] = {0.0f,
1114 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1115 bc.buffer->get_drop_shadow_softener(),
1116 0.0};
1117 bgfx::setUniform(u_params_, &params);
1118 break;
1119 }
1120
1122 {
1123 program = distance_outline_drop_shadow_image_program_;
1124 bgfx::setState(state | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_RGB |
1125 BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA));
1126
1127 uint32_t drop_shadow_color = bc.buffer->get_drop_shadow_color();
1128 float drop_shadow_color_vec[4] = {((drop_shadow_color >> 16) & 0xff) / 255.0f,
1129 ((drop_shadow_color >> 8) & 0xff) / 255.0f,
1130 (drop_shadow_color & 0xff) / 255.0f,
1131 (drop_shadow_color >> 24) / 255.0f};
1132 bgfx::setUniform(u_drop_shadow_color_, &drop_shadow_color_vec);
1133
1134 float params[4] = {0.0f,
1135 (float)font_manager_->get_atlas(fhandle)->getTextureSize() / 512.0f,
1136 bc.buffer->get_drop_shadow_softener(),
1137 bc.buffer->get_outline_width()};
1138 bgfx::setUniform(u_params_, &params);
1139 break;
1140 }
1141
1142 default:
1143 break;
1144 }
1145
1146 switch(bc.type)
1147 {
1149 {
1150 bgfx::IndexBufferHandle ibh;
1151 bgfx::VertexBufferHandle vbh;
1152
1153 if(bgfx::kInvalidHandle == bc.vertex_buffer_handle_idx)
1154 {
1155 ibh = bgfx::createIndexBuffer(bgfx::copy(bc.buffer->get_index_buffer(), index_size));
1156
1157 vbh = bgfx::createVertexBuffer(bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size), vertex_layout_);
1158
1159 bc.vertex_buffer_handle_idx = vbh.idx;
1160 bc.index_buffer_handle_idx = ibh.idx;
1161 }
1162 else
1163 {
1164 vbh.idx = bc.vertex_buffer_handle_idx;
1165 ibh.idx = bc.index_buffer_handle_idx;
1166 }
1167
1168 bgfx::setVertexBuffer(0, vbh, 0, bc.buffer->get_vertex_count());
1169 bgfx::setIndexBuffer(ibh, 0, bc.buffer->get_index_count());
1170 }
1171 break;
1172
1174 {
1175 bgfx::DynamicIndexBufferHandle ibh;
1176 bgfx::DynamicVertexBufferHandle vbh;
1177
1178 if(bgfx::kInvalidHandle == bc.vertex_buffer_handle_idx)
1179 {
1180 ibh = bgfx::createDynamicIndexBuffer(bgfx::copy(bc.buffer->get_index_buffer(), index_size),
1181 BGFX_BUFFER_ALLOW_RESIZE);
1182
1183 vbh = bgfx::createDynamicVertexBuffer(bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size),
1184 vertex_layout_,
1185 BGFX_BUFFER_ALLOW_RESIZE);
1186
1187 bc.index_buffer_handle_idx = ibh.idx;
1188 bc.vertex_buffer_handle_idx = vbh.idx;
1189 }
1190 else if(bc.buffer->get_buffers_dirty())
1191 {
1192 ibh.idx = bc.index_buffer_handle_idx;
1193 vbh.idx = bc.vertex_buffer_handle_idx;
1194
1195 bgfx::update(ibh, 0, bgfx::copy(bc.buffer->get_index_buffer(), index_size));
1196
1197 bgfx::update(vbh, 0, bgfx::copy(bc.buffer->get_vertex_buffer(), vertex_size));
1198 }
1199
1200 ibh.idx = bc.index_buffer_handle_idx;
1201 vbh.idx = bc.vertex_buffer_handle_idx;
1202
1203 bgfx::setVertexBuffer(0, vbh, 0, bc.buffer->get_vertex_count());
1204 bgfx::setIndexBuffer(ibh, 0, bc.buffer->get_index_count());
1205 }
1206 break;
1207
1209 {
1210 bgfx::TransientIndexBuffer tib;
1211 bgfx::TransientVertexBuffer tvb;
1212 bgfx::allocTransientIndexBuffer(&tib, bc.buffer->get_index_count());
1213 bgfx::allocTransientVertexBuffer(&tvb, bc.buffer->get_vertex_count(), vertex_layout_);
1214 bx::memCopy(tib.data, bc.buffer->get_index_buffer(), index_size);
1215 bx::memCopy(tvb.data, bc.buffer->get_vertex_buffer(), vertex_size);
1216 bgfx::setVertexBuffer(0, &tvb, 0, bc.buffer->get_vertex_count());
1217 bgfx::setIndexBuffer(&tib, 0, bc.buffer->get_index_count());
1218 }
1219 break;
1220 }
1221
1222 bgfx::submit(id, program, depth);
1223
1224 bc.buffer->set_buffers_dirty(false);
1225}
1226
1227void text_buffer_manager::set_style(text_buffer_handle handle, uint32_t flags)
1228{
1229 BX_ASSERT(isValid(handle), "Invalid handle used");
1230 buffer_cache& bc = text_buffers_[handle.idx];
1231 bc.buffer->set_style(flags);
1232}
1233
1234void text_buffer_manager::set_text_color(text_buffer_handle handle, uint32_t rgba)
1235{
1236 BX_ASSERT(isValid(handle), "Invalid handle used");
1237 buffer_cache& bc = text_buffers_[handle.idx];
1238 bc.buffer->set_text_color(rgba);
1239}
1240
1241void text_buffer_manager::set_background_color(text_buffer_handle handle, uint32_t rgba)
1242{
1243 BX_ASSERT(isValid(handle), "Invalid handle used");
1244 buffer_cache& bc = text_buffers_[handle.idx];
1245 bc.buffer->set_background_color(rgba);
1246}
1247
1248void text_buffer_manager::set_foreground_color(text_buffer_handle handle, uint32_t rgba)
1249{
1250 BX_ASSERT(isValid(handle), "Invalid handle used");
1251 buffer_cache& bc = text_buffers_[handle.idx];
1252 bc.buffer->set_foreground_color(rgba);
1253}
1254
1255void text_buffer_manager::set_overline_color(text_buffer_handle handle, uint32_t rgba)
1256{
1257 BX_ASSERT(isValid(handle), "Invalid handle used");
1258 buffer_cache& bc = text_buffers_[handle.idx];
1259 bc.buffer->set_overline_color(rgba);
1260}
1261
1262void text_buffer_manager::set_underline_color(text_buffer_handle handle, uint32_t rgba)
1263{
1264 BX_ASSERT(isValid(handle), "Invalid handle used");
1265 buffer_cache& bc = text_buffers_[handle.idx];
1266 bc.buffer->set_underline_color(rgba);
1267}
1268
1269void text_buffer_manager::set_strike_through_color(text_buffer_handle handle, uint32_t rgba)
1270{
1271 BX_ASSERT(isValid(handle), "Invalid handle used");
1272 buffer_cache& bc = text_buffers_[handle.idx];
1273 bc.buffer->set_strike_through_color(rgba);
1274}
1275
1276void text_buffer_manager::set_outline_color(text_buffer_handle handle, uint32_t rgba)
1277{
1278 BX_ASSERT(isValid(handle), "Invalid handle used");
1279 buffer_cache& bc = text_buffers_[handle.idx];
1280 bc.buffer->set_outline_color(rgba);
1281}
1282
1283void text_buffer_manager::set_outline_width(text_buffer_handle handle, float outline_width)
1284{
1285 BX_ASSERT(isValid(handle), "Invalid handle used");
1286 buffer_cache& bc = text_buffers_[handle.idx];
1287 bc.buffer->set_outline_width(outline_width);
1288}
1289
1290void text_buffer_manager::set_drop_shadow_color(text_buffer_handle handle, uint32_t rgba)
1291{
1292 BX_ASSERT(isValid(handle), "Invalid handle used");
1293 buffer_cache& bc = text_buffers_[handle.idx];
1294 bc.buffer->set_drop_shadow_color(rgba);
1295}
1296
1297void text_buffer_manager::set_drop_shadow_offset(text_buffer_handle handle, float u, float v)
1298{
1299 BX_ASSERT(isValid(handle), "Invalid handle used");
1300 buffer_cache& bc = text_buffers_[handle.idx];
1301 bc.buffer->set_drop_shadow_offset(u, v);
1302}
1303
1304void text_buffer_manager::set_drop_shadow_softener(text_buffer_handle handle, float smoother)
1305{
1306 BX_ASSERT(isValid(handle), "Invalid handle used");
1307 buffer_cache& bc = text_buffers_[handle.idx];
1308 bc.buffer->set_drop_shadow_softener(smoother);
1309}
1310
1311void text_buffer_manager::set_pen_position(text_buffer_handle handle, float x, float y)
1312{
1313 BX_ASSERT(isValid(handle), "Invalid handle used");
1314 buffer_cache& bc = text_buffers_[handle.idx];
1315 bc.buffer->set_pen_position(x, y);
1316}
1317
1318void text_buffer_manager::set_pen_origin(text_buffer_handle handle, float x, float y)
1319{
1320 BX_ASSERT(isValid(handle), "Invalid handle used");
1321 buffer_cache& bc = text_buffers_[handle.idx];
1322 bc.buffer->set_pen_origin(x, y);
1323}
1324
1325void text_buffer_manager::get_pen_position(text_buffer_handle handle, float* x, float* y)
1326{
1327 BX_ASSERT(isValid(handle), "Invalid handle used");
1328 buffer_cache& bc = text_buffers_[handle.idx];
1329 bc.buffer->get_pen_position(x, y);
1330}
1331
1332void text_buffer_manager::set_apply_kerning(text_buffer_handle handle, bool apply_kerning)
1333{
1334 BX_ASSERT(isValid(handle), "Invalid handle used");
1335 buffer_cache& bc = text_buffers_[handle.idx];
1336 bc.buffer->set_apply_kerning(apply_kerning);
1337}
1338
1340 font_handle fhandle,
1341 const char* _string,
1342 const char* _end)
1343{
1344 BX_ASSERT(isValid(handle), "Invalid handle used");
1345 buffer_cache& bc = text_buffers_[handle.idx];
1346 bc.buffer->append_text(fhandle, _string, _end);
1347}
1348
1350 font_handle fhandle,
1351 const wchar_t* _string,
1352 const wchar_t* _end)
1353{
1354 BX_ASSERT(isValid(handle), "Invalid handle used");
1355 buffer_cache& bc = text_buffers_[handle.idx];
1356 bc.buffer->append_text(fhandle, _string, _end);
1357}
1358
1359void text_buffer_manager::append_atlas_face(text_buffer_handle handle, font_handle fhandle, uint16_t _faceIndex)
1360{
1361 BX_ASSERT(isValid(handle), "Invalid handle used");
1362 buffer_cache& bc = text_buffers_[handle.idx];
1363 bc.buffer->append_atlas_face(fhandle, _faceIndex);
1364}
1365
1367{
1368 BX_ASSERT(isValid(handle), "Invalid handle used");
1369 buffer_cache& bc = text_buffers_[handle.idx];
1370 bc.buffer->clear_text_buffer();
1371}
1372
1374{
1375 BX_ASSERT(isValid(handle), "Invalid handle used");
1376 buffer_cache& bc = text_buffers_[handle.idx];
1377 return bc.buffer->get_rectangle();
1378}
1379
1380} // 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:271
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