3#include <hpp/string_view.hpp>
7#include <libunibreak/graphemebreak.h>
8#include <libunibreak/linebreak.h>
9#include <libunibreak/linebreakdef.h>
10#include <libunibreak/unibreakdef.h>
19constexpr float PIXELS_PER_METER = 10.0f;
21constexpr float METERS_PER_PIXEL = 1.0f / PIXELS_PER_METER;
23auto fade(uint32_t c,
float alphaMultiplier) -> uint32_t
30auto can_batch_with(
const text_style& lhs,
const text_style& rhs) ->
bool
32 constexpr float EPS = 1e-6f;
33 auto feq = [&](
float a,
float b)
35 return std::fabs(
a -
b) < EPS;
38 return feq(lhs.outline_width, rhs.outline_width) && feq(lhs.shadow_softener, rhs.shadow_softener) &&
39 fade(lhs.shadow_color, lhs.opacity) == fade(rhs.shadow_color, rhs.opacity);
59auto safe_parse_float(hpp::string_view
const& s,
float def = 0.0f) ->
float
65 std::string tmp(
s.data(),
s.size());
66 char* endptr =
nullptr;
68 float v = std::strtof(tmp.c_str(), &endptr);
69 if(errno == 0 && endptr == tmp.c_str() + tmp.size())
83static constexpr std::pair<hpp::string_view, uint32_t> k_named_colors[] = {
84 {
"black", 0xFF000000u },
85 {
"white", 0xFFFFFFFFu },
86 {
"red", 0xFF0000FFu },
87 {
"green", 0xFF00FF00u },
88 {
"blue", 0xFFFF0000u },
89 {
"yellow", 0xFF00FFFFu },
90 {
"cyan", 0xFFFFFF00u },
91 {
"magenta", 0xFFFF00FFu },
92 {
"gray", 0xFF808080u },
93 {
"grey", 0xFF808080u },
94 {
"orange", 0xFF00A5FFu },
95 {
"purple", 0xFF800080u },
96 {
"pink", 0xFFCBC0FFu },
97 {
"brown", 0xFF2A2AFFu },
98 {
"maroon", 0xFF000080u },
99 {
"olive", 0xFF008080u },
100 {
"navy", 0xFF800000u },
101 {
"teal", 0xFF808000u },
102 {
"silver", 0xFFC0C0C0u },
103 {
"gold", 0xFF00D7FFu },
106auto hex_nib(
char c) -> uint8_t
108 if(c >=
'0' && c <=
'9')
112 if(c >=
'a' && c <=
'f')
116 if(c >=
'A' && c <=
'F')
122auto parse_color(hpp::string_view s) -> uint32_t
125 if(!
s.empty() && s[0] ==
'#')
127 auto nib = [&](
char c)
129 if(c >=
'0' && c <=
'9')
131 return uint8_t(c -
'0');
133 if(c >=
'a' && c <=
'f')
135 return uint8_t(c -
'a' + 10);
137 if(c >=
'A' && c <=
'F')
139 return uint8_t(c -
'A' + 10);
144 const char*
p =
s.data() + 1;
145 uint8_t
r = nib(p[0]) << 4 | nib(p[1]);
146 uint8_t
g = nib(p[2]) << 4 | nib(p[3]);
147 uint8_t
b = nib(p[4]) << 4 | nib(p[5]);
148 uint8_t
a = (
s.size() == 9) ? (nib(p[6]) << 4 | nib(p[7])) : 0xFFu;
152 return static_cast<uint32_t
>(col);
156 for(
auto& kv : k_named_colors)
174auto parse_rich_segments(
const hpp::string_view& in,
const text_style& main_style,
bool is_rich) ->
segment_list
179 out.emplace_back(rich_segment{.text = in, .state = {.style = main_style}});
185 open_tags.reserve(16);
186 open_tags.emplace_back(rich_state{.style = main_style}, hpp::string_view{});
188 size_t pos = 0, text_start = 0, len = in.size();
192 size_t open = in.find(
'<', pos);
193 if(open == hpp::string_view::npos)
199 if(open > text_start)
201 out.push_back({hpp::string_view(in.data() + text_start, open - text_start), open_tags.back().first});
205 size_t close = in.find(
'>', open + 1);
206 if(close == hpp::string_view::npos)
209 out.push_back({.text=hpp::string_view(in.data() + open, 1), .state=open_tags.back().first});
216 size_t stray = in.find(
'<', open + 1);
217 if(stray != hpp::string_view::npos && stray < close)
220 out.push_back({.text = hpp::string_view(in.data() + open, 1), .state = open_tags.back().first});
227 auto inner = in.substr(open + 1, close - open - 1);
234 out.push_back({.text = hpp::string_view(in.data() + open, 2), .state = open_tags.back().first});
242 auto name = inner.substr(1);
246 for(
auto it = open_tags.rbegin(); it != open_tags.rend(); ++it)
248 if(it->second ==
name)
250 open_tags.erase(std::next(it).base());
260 {.text = hpp::string_view(in.data() + open, close - open + 1), .state = open_tags.back().first});
266 size_t eq = inner.find(
'=');
267 hpp::string_view
key = eq == hpp::string_view::npos ? inner : inner.substr(0, eq);
268 hpp::string_view val = eq == hpp::string_view::npos ? hpp::string_view{} : inner.substr(eq + 1);
270 rich_state ns = open_tags.back().first;
271 bool recognized =
true;
275 ns.style.text_color = parse_color(val);
277 else if(key ==
"alpha" || key ==
"opacity")
280 float f = safe_parse_float(val, 1.0f);
281 f = math::clamp(f, 0.0f, 1.0f);
282 ns.style.opacity *=
f;
284 else if(key ==
"background-color" || key ==
"bgcolor")
286 ns.style.background_color = parse_color(val);
289 else if(key ==
"foreground-color" || key ==
"fgcolor")
291 ns.style.foreground_color = parse_color(val);
294 else if(key ==
"overline-color")
296 ns.style.overline_color = parse_color(val);
299 else if(key ==
"overline" || key ==
"o")
301 ns.style.overline_color = ns.style.text_color;
304 else if(key ==
"underline-color")
306 ns.style.underline_color = parse_color(val);
309 else if(key ==
"underline" || key ==
"u")
311 ns.style.underline_color = ns.style.text_color;
314 else if(key ==
"strikethrough-color" || key ==
"strike-color")
316 ns.style.strike_color = parse_color(val);
319 else if(key ==
"strikethrough" || key ==
"s")
321 ns.style.strike_color = ns.style.text_color;
324 else if(key ==
"outline-width")
326 ns.style.outline_width = safe_parse_float(val);
328 else if(key ==
"outline-color")
330 ns.style.outline_color = parse_color(val);
332 else if(key ==
"shadow-offset" || key ==
"drop-shadow-offset")
334 std::string tmp(val);
335 std::replace(tmp.begin(), tmp.end(),
',',
' ');
336 std::istringstream ss(tmp);
337 ss >> ns.style.shadow_offsets.x >> ns.style.shadow_offsets.y;
339 else if(key ==
"shadow-color" || key ==
"drop-shadow-color")
341 ns.style.shadow_color = parse_color(val);
343 else if(key ==
"shadow-softener" || key ==
"drop-shadow-softener")
345 ns.style.shadow_softener = safe_parse_float(val);
347 else if(key ==
"nobr")
351 else if(key ==
"style")
355 while(p < val.size())
357 auto c = val.find_first_of(
"|,", p);
358 auto sub = val.substr(p, c == hpp::string_view::npos ? hpp::string_view::npos : c - p);
359 if(sub ==
"underline")
363 else if(sub ==
"overline")
367 else if(sub ==
"strikethrough" || sub ==
"strike")
371 else if(sub ==
"background")
375 else if(sub ==
"foreground")
379 if(c == hpp::string_view::npos)
385 ns.style.style_flags =
f;
391 {.text = hpp::string_view(in.data() + open, close - open + 1), .state = open_tags.back().first});
396 open_tags.emplace_back(ns, key);
403 {.text = hpp::string_view(in.data() + text_start, len - text_start), .state = open_tags.back().first});
414 m.metrics.append_text(base_font.handle,
f.txt.data(),
f.txt.data() +
f.txt.size());
415 f.base_width =
m.metrics.get_width();
416 f.scaled_width =
f.base_width;
420auto measure_line_width(
segment_list& frags,
const scaled_font& base_font) ->
float
426 m.metrics.append_text(base_font.handle,
f.text.data(),
f.text.data() +
f.text.size());
427 w +=
m.metrics.get_width();
433auto measure_text_width(
const hpp::string_view& txt,
const scaled_font& base_font) ->
float
436 m.metrics.append_text(base_font.handle, txt.data(), txt.data() + txt.size());
437 return m.metrics.get_width();
452auto get_next_char_frag(
const void* ctx_void,
457 auto const* ctx =
static_cast<const linebreak_ctx*
>(ctx_void);
459 if(pos >= ctx->total_len)
469 size_t seg_idx = (it -
offsets.begin()) - 1;
470 size_t seg_start =
offsets[seg_idx];
471 auto const& txt =
segments[seg_idx].text;
473 size_t local_ip = pos - seg_start;
474 assert(local_ip <= txt.size());
476 auto txt_data = txt.data();
477 auto txt_size = txt.size();
480 utf32_t cp = ub_get_next_char_utf8(
reinterpret_cast<const utf8_t*
>(txt_data), txt_size, &local_ip);
483 *ip = seg_start + local_ip;
489 const scaled_font&
font,
493 auto& frags =
cache.frags;
498 cache.offsets[0] = 0;
507 ctx.offsets = &
cache.offsets;
508 ctx.total_len =
cache.offsets.back();
511 cache.lb.resize(ctx.total_len);
515 cache.wb.resize(ctx.total_len);
529 set_graphemebreaks(&ctx, ctx.total_len,
cache.wb.data(), get_next_char_frag);
533 for(
size_t seg_i = 0; seg_i <
segments.size(); ++seg_i)
536 auto const& state = seg.state;
537 auto const&
s = seg.text;
538 size_t const base =
cache.offsets[seg_i];
546 bool found_lb =
false;
547 bool found_wb =
false;
548 size_t break_end = 0;
553 unsigned char b0 =
s[idx];
554 size_t cp_len = (b0 < 0x80 ? 1 : (b0 < 0xE0 ? 2 : (b0 < 0xF0 ? 3 : 4)));
560 size_t global_cp_end = base + idx + cp_len;
561 char lbv =
cache.lb[global_cp_end - 1];
562 if(lbv == LINEBREAK_MUSTBREAK)
566 break_end = idx + cp_len;
571 if(lbv == LINEBREAK_ALLOWBREAK)
574 break_end = idx + cp_len;
580 char wbv =
cache.wb[global_cp_end - 1];
581 if(wbv == GRAPHEMEBREAK_BREAK)
584 break_end = idx + cp_len;
595 if(!found_lb && !found_wb)
602 std::string_view slice(
s.data() + start, frag_len);
603 std::string_view break_slice(
s.data() + start + frag_len, 0);
605 auto w = measure_text_width(slice,
font);
606 frags.push_back({slice, break_slice, state, brk,
w,
w});
613 size_t cp0 = break_end - 1;
614 while(cp0 > start && (uint8_t(s[cp0]) & 0xC0) == 0x80)
622 frag_len = cp0 -
start;
628 frag_len = break_end -
start;
632 std::string_view slice(
s.data() + start, frag_len);
633 std::string_view break_slice(
s.data() + start + frag_len, break_end - (start + frag_len));
635 auto w = measure_text_width(slice,
font);
636 frags.push_back({slice, break_slice, state, brk,
w,
w});
651auto compute_typographic_height(
float total_h,
float above_capline,
float below_baseline, uint32_t alignment) ->
float
660 return total_h - (above_capline + below_baseline);
663auto apply_typographic_adjustment(
float total_h,
float scale,
const scaled_font& fnt, uint32_t alignment) ->
float
665 const auto& info = fnt.get_info();
666 float above_capline = info.ascender - info.capline;
668 float below_baseline = -info.descender;
670 return compute_typographic_height(total_h, above_capline *
scale, below_baseline *
scale, alignment);
676void merge_into_line(
segment_list& line,
const word_frag& f)
678 if(!line.empty() && can_batch_with(line.back().state.style,
f.state.style) &&
679 line.back().text.data() + line.back().text.size() ==
f.txt.data())
682 auto&
back = line.back();
683 back.text = {
back.text.data(),
back.text.size() +
f.txt.size()};
687 line.push_back({
f.txt,
f.state});
697 auto& atoms =
cache.atoms;
699 atoms.reserve(frags.size());
703 cur.parts.reserve(4);
704 for(
auto const& f : frags)
706 cur.parts.push_back(f);
707 cur.width +=
f.scaled_width;
711 atoms.push_back(std::move(cur));
713 cur.parts.reserve(4);
716 if(!cur.parts.empty())
719 atoms.push_back(std::move(cur));
725 lines.reserve(atoms.size());
727 wrapped_line cur_line;
728 cur_line.segments.reserve(16);
731 for(
auto& atom : atoms)
734 if(cur_w + atom.width > max_width_px && !cur_line.segments.empty())
736 cur_line.width = cur_w;
737 lines.push_back(std::move(cur_line));
739 cur_line.segments.reserve(16);
744 for(
auto& frag : atom.parts)
746 merge_into_line(cur_line.segments, frag);
753 cur_line.width = cur_w;
754 if(!atom.parts.empty())
756 cur_line.brk_symbol = atom.parts.back().brk_symbol;
758 lines.push_back(std::move(cur_line));
760 cur_line.segments.reserve(16);
766 if(!cur_line.segments.empty())
768 cur_line.width = cur_w;
769 lines.push_back(std::move(cur_line));
781 scratch_cache&
cache,
782 uint32_t& calculated_font_size,
789 uint32_t base_size = auto_size_range.min;
790 auto base_font =
font.get()->get_scaled_font(base_size);
796 uint32_t best = base_size;
799 uint32_t lo = base_size + 1, hi = auto_size_range.max;
802 uint32_t mid = (lo + hi) >> 1;
803 float scale = float(mid) / float(base_size);
808 f.scaled_width =
f.base_width *
scale;
812 auto layout_mid = wrap_fragments(frags, bound_w_px,
cache);
815 float total_h = layout_mid.size() * (base_font->get_line_height() *
scale);
816 total_h = apply_typographic_adjustment(total_h,
scale, *base_font, alignment);
818 if(total_h > bound_h_px)
826 for(
auto& wl : layout_mid)
828 if(wl.width > bound_w_px)
839 best_layout = std::move(layout_mid);
850 calculated_font_size = best;
857 scratch_cache&
cache,
858 const scaled_font&
font,
865 return wrap_fragments(frags, max_width_px,
cache);
873auto compute_vertical_offset(uint32_t alignment,
877 float below_baseline) ->
float
879 float bounds_h_px = bounds_h_m * PIXELS_PER_METER;
881 float usable_h = compute_typographic_height(total_h, above_capline, below_baseline, alignment);
889 return (bounds_h_px - total_h) * 0.5f;
891 return (bounds_h_px - total_h);
893 return -above_capline;
895 return -above_capline + (bounds_h_px - usable_h) * 0.5f;
897 return below_baseline + (bounds_h_px - total_h);
903auto compute_horizontal_offset(uint32_t alignment,
float bounds_width_m,
float line_width_px) ->
float
905 float bounds_width_px = bounds_width_m * PIXELS_PER_METER;
910 offset_px = (bounds_width_px - line_width_px) * 0.5f;
913 offset_px = (bounds_width_px - line_width_px);
969 if(overflow_type_ ==
type)
973 overflow_type_ =
type;
978 return overflow_type_;
983 if(font_ ==
font && font_version_ ==
font.version())
989 scaled_font_dirty_ =
true;
999 if(font_.version() != font_version_ || scaled_font_dirty_)
1001 recreate_scaled_font();
1006 return *scaled_font_;
1015 bool dirty = text_dirty_ || scaled_font_dirty_;
1023 uint32_t alignment = align_.
flags;
1031 auto segments = parse_rich_segments(text_, style_, is_rich_);
1034 float bound_w = area_.
width * PIXELS_PER_METER;
1035 float bound_h = area_.
height * PIXELS_PER_METER;
1043 calculated_font_size_ = font_size_;
1044 scaled_font_ = font_.get()->get_scaled_font(calculated_font_size_);
1045 auto& fixed_font = *scaled_font_;
1047 layout = wrap_fixed_size(overflow_type_,
segments, scratch_, fixed_font, bound_w);
1056 layout = wrap_lines(overflow_type_,
1060 calculated_font_size_,
1062 auto_size_font_range_,
1066 scaled_font_ = font_.get()->get_scaled_font(calculated_font_size_);
1069 auto& final_font = *scaled_font_;
1072 const auto& info = final_font.get_info();
1073 float line_h = final_font.get_line_height();
1074 float above_capline = info.ascender - info.capline;
1075 float below_baseline = -info.descender;
1077 float total_h = float(layout.size()) * line_h;
1078 float offset_y = compute_vertical_offset(alignment, area_.
height, total_h, above_capline, below_baseline);
1081 float pen_y = offset_y;
1084 builder_->destroy_buffers();
1085 debug_builder_->destroy_buffers();
1087 rich_segment* last_segment{};
1088 for(
auto& wl : layout)
1090 float offset_x = compute_horizontal_offset(alignment, area_.
width, wl.width);
1091 float pen_x = offset_x;
1093 for(
auto& seg : wl.segments)
1095 bool create_new = !(last_segment && can_batch_with(last_segment->state.style, seg.state.style));
1099 builder_->buffers.push_back({buf});
1102 auto& buf = builder_->buffers.back().handle;
1103 apply_style(builder_->manager, buf, seg.state.style);
1104 builder_->manager.set_apply_kerning(buf, apply_kerning_);
1105 builder_->manager.set_pen_origin(buf, offset_x, offset_y);
1106 builder_->manager.set_pen_position(buf, pen_x, pen_y);
1107 builder_->manager.append_text(buf, final_font.handle, seg.text.data(), seg.text.data() + seg.text.size());
1108 builder_->manager.get_pen_position(buf, &pen_x, &pen_y);
1110 last_segment = &seg;
1129 text_dirty_ =
false;
1130 scaled_font_dirty_ =
false;
1136 if(font_size_ == font_size)
1140 font_size_ = font_size;
1142 scaled_font_dirty_ =
true;
1152 if(auto_size_ == auto_size)
1157 auto_size_ = auto_size;
1168 return calculated_font_size_;
1173 if(is_rich_ == is_rich)
1189 if(apply_kerning_ == apply_kerning)
1194 apply_kerning_ = apply_kerning;
1200 return apply_kerning_;
1237 if(auto_size_font_range_ ==
range)
1242 auto_size_font_range_ =
range;
1248 return auto_size_font_range_;
1255 bbox.
min.x = -area.width * 0.5f;
1256 bbox.min.y = area.height * 0.5f;
1259 bbox.max.x = area.width * 0.5f;
1260 bbox.max.y = -area.height * 0.5f;
1261 bbox.max.z = 0.001f;
1270 bbox.
min.x = -area.width * 0.5f;
1271 bbox.min.y = area.height * 0.5f;
1274 bbox.max.x = area.width * 0.5f;
1275 bbox.max.y = -area.height * 0.5f;
1276 bbox.max.z = 0.001f;
1283 return get_builder().buffers.size();
1288 auto& builder = get_builder();
1289 auto& layout = scratch_.layout;
1292 lines.reserve(layout.size());
1293 for(
const auto& layout_line : layout)
1295 auto& line = lines.emplace_back();
1297 for(
auto& seg : layout_line.segments)
1299 line.line += std::string(seg.text);
1304 line.break_symbol = std::string(layout_line.brk_symbol);
1313 return meters * PIXELS_PER_METER;
1317 return px * METERS_PER_PIXEL;
1330 const auto& builder = get_builder();
1332 for(
auto& sb : builder.buffers)
1334 auto r = builder.manager.get_rectangle(sb.handle);
1336 result.
width = std::max(result.
width, r.width);
1341 result.
width = std::max(result.
width * METERS_PER_PIXEL, area.width);
1342 result.
height = std::max(result.
height * METERS_PER_PIXEL, area.height);
1346void text_component::recreate_scaled_font()
const
1348 font_version_ = font_.version();
1352 scaled_font_.reset();
1355 auto font = font_.get();
1358 scaled_font_.reset();
1371 float fit_px_w = fit_m.width * PIXELS_PER_METER;
1372 float fit_px_h = fit_m.height * PIXELS_PER_METER;
1375 pivot.
translate(-fit_px_w * 0.5f, -fit_px_h * 0.5f);
1379 auto text_transform = world * unit_scale * pivot;
1380 auto& builder = get_builder();
1384 for(
auto& sb : builder.buffers)
1387 builder.manager.submit_text_buffer(sb.handle,
font.
handle,
id, state);
1390 for(
auto& sb : debug_builder_->buffers)
1393 debug_builder_->manager.submit_text_buffer(sb.handle,
font.
handle,
id, state);
void set_foreground_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
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)
void set_style(text_buffer_handle handle, uint32_t flags=style_normal)
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)
void set_drop_shadow_color(text_buffer_handle handle, uint32_t rgba=0x000000FF)
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 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)
void set_buffer_type(const buffer_type &type)
Sets the buffer type for text rendering.
auto get_style() const -> const text_style &
Gets the current text style settings.
auto get_apply_kerning() const -> bool
Checks if kerning is enabled.
auto get_area() const -> const fsize_t &
Gets the current text area bounds.
void set_alignment(const alignment &align)
Sets the text alignment properties.
auto get_render_font_size() const -> uint32_t
Gets the actual font size being used for rendering.
void set_font(const asset_handle< font > &font)
Sets the font to be used for rendering text.
auto get_auto_size() const -> bool
Checks if auto-sizing is enabled.
auto get_auto_size_range() const -> const urange32_t &
Gets the current auto-size range.
auto get_font_size() const -> uint32_t
Gets the current font size.
auto get_bounds() const -> math::bbox
Gets the bounding box of the text.
auto get_lines(bool include_breaks=true) const -> text_vector< text_line >
Gets the text content split into lines.
auto get_font() const -> const asset_handle< font > &
Gets the current font.
void set_area(const fsize_t &area)
Sets the area bounds for text rendering.
void set_is_rich_text(bool is_rich)
Enables or disables rich text processing.
auto get_text() const -> const std::string &
Gets the current text content.
void set_overflow_type(const overflow_type &type)
Sets how text should overflow when it exceeds its bounds.
auto get_alignment() const -> const alignment &
Gets the current text alignment settings.
auto get_is_rich_text() const -> bool
Checks if rich text processing is enabled.
auto meters_to_px(float meters) const -> float
Converts meters to pixels based on current font metrics.
auto get_render_area() const -> fsize_t
Gets the actual area used for rendering.
void set_text(const std::string &text)
Sets the text content to be rendered.
auto get_scaled_font() const -> const scaled_font &
Gets the scaled font instance used for rendering.
auto px_to_meters(float px) const -> float
Converts pixels to meters based on current font metrics.
void submit(gfx::view_id id, const math::transform &world, uint64_t state)
Submits the text for rendering.
void set_auto_size(bool auto_size)
Enables or disables automatic font sizing.
void set_font_size(uint32_t font_size)
Sets the font size in pixels.
auto get_render_bounds() const -> math::bbox
Gets the bounding box used for rendering.
auto get_overflow_type() const -> const overflow_type &
Gets the current overflow handling type.
void set_auto_size_range(const urange32_t &range)
Sets the range for automatic font sizing.
auto get_render_buffers_count() const -> size_t
Gets the number of render buffers being used.
auto get_buffer_type() const -> const buffer_type &
Gets the current buffer type.
auto can_be_rendered() const -> bool
Checks if the text can be rendered.
void set_style(const text_style &style)
Sets the text styling properties.
void set_apply_kerning(bool apply_kerning)
Enables or disables kerning in text rendering.
#define FONT_TYPE_DISTANCE_OUTLINE_DROP_SHADOW_IMAGE
uint32_t set_transform(const void *_mtx, uint16_t _num)
void close(const std::string &scope)
Closes the specified scope.
auto start(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Starts a new action.
text_vector< word_frag > fragment_list
text_vector< rich_segment > segment_list
hpp::small_vector< T, StaticCapacity > text_vector
text_vector< wrapped_line > text_layout
const segment_list * segments
const text_vector< size_t > * offsets
Represents a handle to an asset, providing access and management functions.
Storage for box vector values and wraps up common functionality.
vec3 min
The minimum vector value of the bounding box.
auto is_valid() const -> bool