HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
draw_context.hpp
1// Copyright Take Vos 2020-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "pipeline_box_vertex.hpp"
8#include "pipeline_image_vertex.hpp"
9#include "pipeline_SDF_vertex.hpp"
10#include "pipeline_alpha_vertex.hpp"
16#include "../geometry/transform.hpp"
19#include "../unicode/unicode_bidi_class.hpp"
20#include "../text/text_cursor.hpp"
21#include "../text/text_selection.hpp"
22#include "../text/text_shaper.hpp"
23#include "../color/color.hpp"
24#include "../color/quad_color.hpp"
26#include "../vector_span.hpp"
27#include "../concepts.hpp"
28
29namespace hi::inline v1 {
30class gfx_device;
31class gfx_device_vulkan;
32class glyph_ids;
33struct paged_image;
34
37enum class border_side {
40 on,
41
44 inside,
45
49};
50
51template<typename Context>
52concept draw_attribute = std::same_as<Context, quad_color> or std::same_as<Context, color> or
53 std::same_as<Context, border_side> or std::same_as<Context, line_end_cap> or std::same_as<Context, corner_radii> or
54 std::same_as<Context, aarectanglei> or std::same_as<Context, float> or std::same_as<Context, int>;
55
57 unsigned char num_colors = 0;
58 unsigned char num_line_caps = 0;
59
60 quad_color fill_color = {};
61 quad_color line_color = {};
62 float line_width = 0.0f;
63 hi::border_side border_side = hi::border_side::on;
64 hi::corner_radii corner_radius = {};
65 aarectanglei clipping_rectangle = aarectanglei::large();
66 line_end_cap begin_line_cap = line_end_cap::flat;
67 line_end_cap end_line_cap = line_end_cap::flat;
68
69 constexpr draw_attributes(draw_attributes const&) noexcept = default;
70 constexpr draw_attributes(draw_attributes&&) noexcept = default;
71 constexpr draw_attributes& operator=(draw_attributes const&) noexcept = default;
72 constexpr draw_attributes& operator=(draw_attributes&&) noexcept = default;
73 constexpr draw_attributes() noexcept = default;
74
75 template<draw_attribute... Args>
76 constexpr draw_attributes(Args const&...args) noexcept
77 {
78 add(args...);
79 }
80
81 constexpr void add() noexcept {}
82
83 template<draw_attribute T>
84 constexpr void add(T const& attribute) noexcept
85 {
86 if constexpr (std::is_same_v<T, quad_color>) {
87 if (num_colors++ == 0) {
88 fill_color = attribute;
89 } else {
90 line_color = attribute;
91 }
92 hi_axiom(num_colors <= 2);
93
94 } else if constexpr (std::is_same_v<T, color>) {
95 if (num_colors++ == 0) {
96 fill_color = quad_color{attribute};
97 } else {
98 line_color = quad_color{attribute};
99 }
100 hi_axiom(num_colors <= 2);
101
102 } else if constexpr (std::is_same_v<T, line_end_cap>) {
103 if (num_line_caps++ == 0) {
104 begin_line_cap = attribute;
105 end_line_cap = attribute;
106 } else {
107 end_line_cap = attribute;
108 }
109 hi_axiom(num_line_caps <= 2);
110
111 } else if constexpr (std::is_same_v<T, hi::border_side>) {
112 border_side = attribute;
113#ifndef NDEBUG
114 hi_assert(not _has_border_side);
115 _has_border_side = true;
116#endif
117
118 } else if constexpr (std::is_same_v<T, corner_radii>) {
119 corner_radius = attribute;
120#ifndef NDEBUG
121 hi_assert(not _has_corner_radii);
122 _has_corner_radii = true;
123#endif
124
125 } else if constexpr (std::is_same_v<T, aarectanglei>) {
126 clipping_rectangle = attribute;
127#ifndef NDEBUG
128 hi_assert(not _has_clipping_rectangle);
129 _has_clipping_rectangle = true;
130#endif
131
132 } else if constexpr (std::is_same_v<T, float> or std::is_same_v<T, int>) {
133 line_width = narrow_cast<float>(attribute);
134#ifndef NDEBUG
135 hi_assert(not _has_line_width);
136 _has_line_width = true;
137#endif
138 } else {
140 }
141 }
142
143 template<draw_attribute First, draw_attribute Second, draw_attribute... Rest>
144 constexpr void add(First const& first, Second const& second, Rest const&...rest) noexcept
145 {
146 add(first);
147 add(second, rest...);
148 }
149
150private:
151#ifndef NDEBUG
152 bool _has_border_side = false;
153 bool _has_corner_radii = false;
154 bool _has_clipping_rectangle = false;
155 bool _has_line_width = false;
156#endif
157};
158
159template<typename Context>
160concept draw_quad_shape = std::same_as<Context, quad> or std::same_as<Context, rectangle> or std::same_as<Context, aarectangle> or
161 std::same_as<Context, aarectanglei>;
162
166public:
167 gfx_device_vulkan& device;
168
172
175 aarectanglei scissor_rectangle;
176
180
183 hi::subpixel_orientation subpixel_orientation;
184
187 bool active;
188
192
195 utc_nanoseconds display_time_point;
196
197 draw_context(draw_context const& rhs) noexcept = default;
198 draw_context(draw_context&& rhs) noexcept = default;
199 draw_context& operator=(draw_context const& rhs) noexcept = default;
200 draw_context& operator=(draw_context&& rhs) noexcept = default;
201 ~draw_context() = default;
202
204 gfx_device_vulkan& device,
208 vector_span<pipeline_alpha::vertex>& alpha_vertices) noexcept;
209
212 operator bool() const noexcept
213 {
214 return frame_buffer_index != std::numeric_limits<size_t>::max();
215 }
216
227 void draw_box(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
228 {
229 return _draw_box(
230 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
231 }
232
233 template<draw_quad_shape Shape, draw_attribute... Attributes>
234 void draw_box(widget_layout const& layout, Shape const& shape, Attributes const&...attributes) const noexcept
235 {
236 return draw_box(layout, make_quad(shape), draw_attributes{attributes...});
237 }
238
239 void draw_line(widget_layout const& layout, line_segment const& line, draw_attributes const& attributes) const noexcept
240 {
241 hilet box =
242 make_rectangle(line, attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
243
244 auto box_attributes = attributes;
245 box_attributes.line_width = 0.0f;
246 box_attributes.fill_color = attributes.line_color;
247 box_attributes.corner_radius =
248 make_corner_radii(attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
249 return draw_box(layout, box, box_attributes);
250 }
251
252 template<draw_attribute... Attributes>
253 void draw_line(widget_layout const& layout, line_segment const& line, Attributes const&...attributes) const noexcept
254 {
255 return draw_line(layout, line, draw_attributes{attributes...});
256 }
257
258 void draw_circle(widget_layout const& layout, hi::circle const& circle, draw_attributes const& attributes) const noexcept
259 {
260 auto box_attributes = attributes;
261 box_attributes.corner_radius = make_corner_radii(circle);
262 return draw_box(layout, make_rectangle(circle), box_attributes);
263 }
264
265 template<draw_attribute... Attributes>
266 void draw_circle(widget_layout const& layout, hi::circle const& circle, Attributes const&...attributes) const noexcept
267 {
268 return draw_circle(layout, circle, draw_attributes{attributes...});
269 }
270
279 [[nodiscard]] bool
280 draw_image(widget_layout const& layout, quad const& box, paged_image& image, draw_attributes const& attributes) const noexcept
281 {
282 return _draw_image(layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, image);
283 }
284
293 template<draw_attribute... Attributes>
294 [[nodiscard]] bool
295 draw_image(widget_layout const& layout, draw_quad_shape auto const& box, paged_image& image, Attributes const&...attributes)
296 const noexcept
297 {
298 return draw_image(layout, make_quad(box), image, draw_attributes{attributes...});
299 }
300
309 void draw_glyph(widget_layout const& layout, quad const& box, glyph_ids const& glyph, draw_attributes const& attributes)
310 const noexcept
311 {
312 return _draw_glyph(
313 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, glyph, attributes);
314 }
315
324 template<draw_quad_shape Shape, draw_attribute... Attributes>
325 void draw_glyph(widget_layout const& layout, Shape const& box, glyph_ids const& glyph, Attributes const&...attributes)
326 const noexcept
327 {
328 return draw_glyph(layout, make_quad(box), glyph, draw_attributes{attributes...});
329 }
330
338 void
339 draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, draw_attributes const& attributes)
340 const noexcept
341 {
342 return _draw_text(
343 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
344 layout.to_window3() * transform,
345 text,
346 attributes);
347 }
348
356 template<draw_attribute... Attributes>
357 void draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, Attributes const&...attributes)
358 const noexcept
359 {
360 return draw_text(layout, transform, text, draw_attributes{attributes...});
361 }
362
370 template<draw_attribute... Attributes>
371 void draw_text(widget_layout const& layout, text_shaper const& text, Attributes const&...attributes) const noexcept
372 {
373 return draw_text(layout, geo::identity{}, text, draw_attributes{attributes...});
374 }
375
384 widget_layout const& layout,
385 text_shaper const& text,
386 text_selection const& selection,
387 draw_attributes const& attributes) const noexcept
388 {
389 return _draw_text_selection(
390 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3(), text, selection, attributes);
391 }
392
400 template<draw_attribute... Attributes>
402 widget_layout const& layout,
403 text_shaper const& text,
404 text_selection const& selection,
405 Attributes const&...attributes) const noexcept
406 {
407 return draw_text_selection(layout, text, selection, draw_attributes{attributes...});
408 }
409
421 widget_layout const& layout,
422 text_shaper const& text,
423 text_cursor cursor,
424 bool overwrite_mode,
425 bool dead_character_mode,
426 draw_attributes const& attributes) const noexcept
427 {
428 return _draw_text_cursors(
429 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
430 layout.to_window3(),
431 text,
432 cursor,
433 overwrite_mode,
434 dead_character_mode,
435 attributes);
436 }
437
448 template<draw_attribute... Attributes>
450 widget_layout const& layout,
451 text_shaper const& text,
452 text_cursor cursor,
453 bool overwrite_mode,
454 bool dead_character_mode,
455 Attributes const&...attributes) const noexcept
456 {
457 return draw_text_cursors(layout, text, cursor, overwrite_mode, dead_character_mode, draw_attributes{attributes...});
458 }
459
468 void draw_hole(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
469 {
470 return _override_alpha(
471 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
472 }
473
482 template<draw_quad_shape Shape, draw_attribute... Attributes>
483 void draw_hole(widget_layout const& layout, Shape const& box, Attributes const&...attributes) const noexcept
484 {
485 return draw_hole(layout, make_quad(box), draw_attributes{attributes...});
486 }
487
488 [[nodiscard]] friend bool overlaps(draw_context const& context, widget_layout const& layout) noexcept
489 {
490 return overlaps(context.scissor_rectangle, layout.clipping_rectangle_on_window());
491 }
492
493private:
494 vector_span<pipeline_box::vertex> *_box_vertices;
495 vector_span<pipeline_image::vertex> *_image_vertices;
496 vector_span<pipeline_SDF::vertex> *_sdf_vertices;
497 vector_span<pipeline_alpha::vertex> *_alpha_vertices;
498
499 template<draw_quad_shape Shape>
500 [[nodiscard]] constexpr static quad make_quad(Shape const& shape) noexcept
501 {
502 if constexpr (std::is_same_v<Shape, aarectanglei>) {
503 return narrow_cast<aarectangle>(shape);
504 } else {
505 return shape;
506 }
507 }
508
509 [[nodiscard]] constexpr static rectangle
510 make_rectangle(line_segment const& line, float width, line_end_cap c1, line_end_cap c2) noexcept
511 {
512 auto right = line.direction();
513
514 hilet radius = width * 0.5f;
515 hilet n = normal(right, 0.0f);
516 hilet up = n * width;
517 hilet t = normalize(right);
518
519 auto origin = line.origin() - n * radius;
520
521 // Extend the line by the radius for rounded end-caps.
522 hilet radius_offset = t * radius;
523 if (c1 == line_end_cap::round) {
524 origin -= radius_offset;
525 right += radius_offset;
526 }
527 if (c2 == line_end_cap::round) {
528 right += radius_offset;
529 }
530
531 return rectangle{origin, right, up};
532 }
533
534 [[nodiscard]] constexpr static rectangle make_rectangle(hi::circle const& circle) noexcept
535 {
536 hilet circle_ = f32x4{circle};
537 hilet origin = point3{circle_.xyz1() - circle_.ww00()};
538 hilet right = vector3{circle_.w000() * 2.0f};
539 hilet up = vector3{circle_._0w00() * 2.0f};
540 return rectangle{origin, right, up};
541 }
542
543 [[nodiscard]] constexpr static corner_radii make_corner_radii(float width, line_end_cap c1, line_end_cap c2) noexcept
544 {
545 auto r = f32x4::broadcast(width * 0.5f);
546
547 if (c1 == line_end_cap::flat) {
548 r = zero<0b0101>(r);
549 }
550 if (c2 == line_end_cap::flat) {
551 r = zero<0b1010>(r);
552 }
553
554 return corner_radii{r};
555 }
556
557 [[nodiscard]] constexpr static corner_radii make_corner_radii(hi::circle const& circle) noexcept
558 {
559 return corner_radii{f32x4{circle}.wwww()};
560 }
561
562 void _override_alpha(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
563
564 void _draw_box(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
565
566 void _draw_text(
567 aarectanglei const& clipping_rectangle,
568 matrix3 const& transform,
569 text_shaper const& text,
570 draw_attributes const& attributes) const noexcept;
571
572 void _draw_text_selection(
573 aarectanglei const& clipping_rectangle,
574 matrix3 const& transform,
575 text_shaper const& text,
576 text_selection const& selection,
577 draw_attributes const& attributes) const noexcept;
578
579 void _draw_text_insertion_cursor_empty(
580 aarectanglei const& clipping_rectangle,
581 matrix3 const& transform,
582 text_shaper const& text,
583 draw_attributes const& attributes) const noexcept;
584
585 void _draw_text_insertion_cursor(
586 aarectanglei const& clipping_rectangle,
587 matrix3 const& transform,
588 text_shaper const& text,
589 text_cursor cursor,
590 bool show_flag,
591 draw_attributes const& attributes) const noexcept;
592
593 void _draw_text_overwrite_cursor(
594 aarectanglei const& clipping_rectangle,
595 matrix3 const& transform,
596 text_shaper::char_const_iterator it,
597 draw_attributes const& attributes) const noexcept;
598
599 void _draw_text_cursors(
600 aarectanglei const& clipping_rectangle,
601 matrix3 const& transform,
602 text_shaper const& text,
603 text_cursor cursor,
604 bool overwrite_mode,
605 bool dead_character_mode,
606 draw_attributes const& attributes) const noexcept;
607
608 void _draw_glyph(
609 aarectanglei const& clipping_rectangle,
610 quad const& box,
611 glyph_ids const& glyph,
612 draw_attributes const& attributes) const noexcept;
613
614 [[nodiscard]] bool _draw_image(aarectanglei const& clipping_rectangle, quad const& box, paged_image& image) const noexcept;
615};
616
617} // namespace hi::inline v1
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:181
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:87
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
Defines identity type.
Defined the corner_radii type.
Defined line_end_cap.
Defined the circle type.
Defines geo::matrix, matrix2 and matrix3.
Defines widget_layout.
@ rectangle
The gui_event has rectangle data.
DOXYGEN BUG.
Definition algorithm.hpp:15
@ circle
<circle> Encircled form.
border_side
The side where the border is drawn.
Definition draw_context.hpp:37
@ inside
The border is drawn inside the edge of a quad.
@ outside
The border is drawn outside the edge of a quad.
@ on
The border is drawn on the edge of a quad.
This is a RGBA floating point color.
Definition color.hpp:39
Definition quad_color.hpp:12
A type defining a 2D circle.
Definition circle.hpp:19
The 4 radiuses of the corners of a quad or rectangle.
Definition corner_radii.hpp:17
Definition quad.hpp:17
Definition draw_context.hpp:56
Draw context for drawing using the HikoGUI shaders.
Definition draw_context.hpp:165
void draw_text_cursors(widget_layout const &layout, text_shaper const &text, text_cursor cursor, bool overwrite_mode, bool dead_character_mode, Attributes const &...attributes) const noexcept
Draw text cursors of shaped text.
Definition draw_context.hpp:449
std::size_t frame_buffer_index
The frame buffer index of the image we are currently rendering.
Definition draw_context.hpp:171
bool draw_image(widget_layout const &layout, quad const &box, paged_image &image, draw_attributes const &attributes) const noexcept
Draw an image.
Definition draw_context.hpp:280
void draw_box(widget_layout const &layout, quad const &box, draw_attributes const &attributes) const noexcept
Draw a box with rounded corners.
Definition draw_context.hpp:227
float saturation
The tone-mapper's saturation.
Definition draw_context.hpp:191
utc_nanoseconds display_time_point
The time when the drawing will appear on the screen.
Definition draw_context.hpp:195
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, Attributes const &...attributes) const noexcept
Draw shaped text.
Definition draw_context.hpp:357
void draw_glyph(widget_layout const &layout, Shape const &box, glyph_ids const &glyph, Attributes const &...attributes) const noexcept
Draw a glyph.
Definition draw_context.hpp:325
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, Attributes const &...attributes) const noexcept
Draw text-selection of shaped text.
Definition draw_context.hpp:401
void draw_glyph(widget_layout const &layout, quad const &box, glyph_ids const &glyph, draw_attributes const &attributes) const noexcept
Draw a glyph.
Definition draw_context.hpp:309
color background_color
The background color to clear the window with.
Definition draw_context.hpp:179
aarectanglei scissor_rectangle
This is the rectangle of the window that is being redrawn.
Definition draw_context.hpp:175
void draw_hole(widget_layout const &layout, Shape const &box, Attributes const &...attributes) const noexcept
Make a hole in the user interface.
Definition draw_context.hpp:483
void draw_text_cursors(widget_layout const &layout, text_shaper const &text, text_cursor cursor, bool overwrite_mode, bool dead_character_mode, draw_attributes const &attributes) const noexcept
Draw text cursors of shaped text.
Definition draw_context.hpp:420
bool draw_image(widget_layout const &layout, draw_quad_shape auto const &box, paged_image &image, Attributes const &...attributes) const noexcept
Draw an image.
Definition draw_context.hpp:295
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, draw_attributes const &attributes) const noexcept
Draw shaped text.
Definition draw_context.hpp:339
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, draw_attributes const &attributes) const noexcept
Draw text-selection of shaped text.
Definition draw_context.hpp:383
hi::subpixel_orientation subpixel_orientation
The subpixel orientation for rendering glyphs.
Definition draw_context.hpp:183
void draw_text(widget_layout const &layout, text_shaper const &text, Attributes const &...attributes) const noexcept
Draw shaped text.
Definition draw_context.hpp:371
bool active
Window is active.
Definition draw_context.hpp:187
void draw_hole(widget_layout const &layout, quad const &box, draw_attributes const &attributes) const noexcept
Make a hole in the user interface.
Definition draw_context.hpp:468
Definition gfx_device_vulkan.hpp:21
This is a image that is uploaded into the texture atlas.
Definition paged_image.hpp:25
A variant of text.
Definition label.hpp:36
A set of glyph-ids of a font which composites into a single glyph.
Definition glyph_ids.hpp:135
A cursor-position in text.
Definition text_cursor.hpp:25
Definition text_selection.hpp:17
Text shaper.
Definition text_shaper.hpp:41
Definition vector_span.hpp:134
Definition draw_context.hpp:52
Definition draw_context.hpp:160
T right(T... args)
T max(T... args)