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"
12#include "../geometry/module.hpp"
13#include "../unicode/unicode_bidi_class.hpp"
14#include "../text/text_cursor.hpp"
15#include "../text/text_selection.hpp"
16#include "../text/text_shaper.hpp"
17#include "../color/module.hpp"
19#include "../vector_span.hpp"
20#include "../utility/module.hpp"
21
22namespace hi { inline namespace v1 {
23class gfx_device;
24class gfx_device_vulkan;
25class glyph_ids;
26struct paged_image;
27
30enum class border_side {
33 on,
34
37 inside,
38
42};
43
44template<typename Context>
45concept draw_attribute = std::same_as<Context, quad_color> or std::same_as<Context, color> or
46 std::same_as<Context, border_side> or std::same_as<Context, line_end_cap> or std::same_as<Context, corner_radii> or
47 std::same_as<Context, aarectanglei> or std::same_as<Context, float> or std::same_as<Context, int>;
48
52 unsigned char num_colors = 0;
53 unsigned char num_line_caps = 0;
54
61
67
70 float line_width = 0.0f;
71
74 hi::border_side border_side = hi::border_side::on;
75
79
86
90
94
95 constexpr draw_attributes(draw_attributes const&) noexcept = default;
96 constexpr draw_attributes(draw_attributes&&) noexcept = default;
97 constexpr draw_attributes& operator=(draw_attributes const&) noexcept = default;
98 constexpr draw_attributes& operator=(draw_attributes&&) noexcept = default;
99 constexpr draw_attributes() noexcept = default;
100
121 template<draw_attribute... Args>
122 constexpr draw_attributes(Args const&...args) noexcept
123 {
124 add(args...);
125 }
126
127 constexpr void add() noexcept {}
128
129 template<draw_attribute T>
130 constexpr void add(T const& attribute) noexcept
131 {
132 if constexpr (std::is_same_v<T, quad_color>) {
133 if (num_colors++ == 0) {
134 fill_color = attribute;
135 } else {
136 line_color = attribute;
137 }
138 hi_axiom(num_colors <= 2);
139
140 } else if constexpr (std::is_same_v<T, color>) {
141 if (num_colors++ == 0) {
142 fill_color = quad_color{attribute};
143 } else {
144 line_color = quad_color{attribute};
145 }
146 hi_axiom(num_colors <= 2);
147
148 } else if constexpr (std::is_same_v<T, line_end_cap>) {
149 if (num_line_caps++ == 0) {
150 begin_line_cap = attribute;
151 end_line_cap = attribute;
152 } else {
153 end_line_cap = attribute;
154 }
155 hi_axiom(num_line_caps <= 2);
156
157 } else if constexpr (std::is_same_v<T, hi::border_side>) {
158 border_side = attribute;
159#ifndef NDEBUG
160 hi_assert(not _has_border_side);
161 _has_border_side = true;
162#endif
163
164 } else if constexpr (std::is_same_v<T, corner_radii>) {
165 corner_radius = attribute;
166#ifndef NDEBUG
167 hi_assert(not _has_corner_radii);
168 _has_corner_radii = true;
169#endif
170
171 } else if constexpr (std::is_same_v<T, aarectanglei>) {
172 clipping_rectangle = attribute;
173#ifndef NDEBUG
174 hi_assert(not _has_clipping_rectangle);
175 _has_clipping_rectangle = true;
176#endif
177
178 } else if constexpr (std::is_same_v<T, float> or std::is_same_v<T, int>) {
179 line_width = narrow_cast<float>(attribute);
180#ifndef NDEBUG
181 hi_assert(not _has_line_width);
182 _has_line_width = true;
183#endif
184 } else {
186 }
187 }
188
189 template<draw_attribute First, draw_attribute Second, draw_attribute... Rest>
190 constexpr void add(First const& first, Second const& second, Rest const&...rest) noexcept
191 {
192 add(first);
193 add(second, rest...);
194 }
195
196private:
197#ifndef NDEBUG
198 bool _has_border_side = false;
199 bool _has_corner_radii = false;
200 bool _has_clipping_rectangle = false;
201 bool _has_line_width = false;
202#endif
203};
204
205template<typename Context>
206concept draw_quad_shape = std::same_as<Context, quad> or std::same_as<Context, rectangle> or std::same_as<Context, aarectangle> or
207 std::same_as<Context, aarectanglei>;
208
212public:
213 gfx_device_vulkan& device;
214
218
222
226
229 hi::subpixel_orientation subpixel_orientation;
230
233 bool active;
234
238
241 utc_nanoseconds display_time_point;
242
243 draw_context(draw_context const& rhs) noexcept = default;
244 draw_context(draw_context&& rhs) noexcept = default;
245 draw_context& operator=(draw_context const& rhs) noexcept = default;
246 draw_context& operator=(draw_context&& rhs) noexcept = default;
247 ~draw_context() = default;
248
250 gfx_device_vulkan& device,
251 vector_span<pipeline_box::vertex>& box_vertices,
252 vector_span<pipeline_image::vertex>& image_vertices,
253 vector_span<pipeline_SDF::vertex>& sdf_vertices,
254 vector_span<pipeline_alpha::vertex>& alpha_vertices) noexcept;
255
258 operator bool() const noexcept
259 {
261 }
262
269 void draw_box(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
270 {
271 return _draw_box(
272 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
273 }
274
281 template<draw_quad_shape Shape, draw_attribute... Attributes>
282 void draw_box(widget_layout const& layout, Shape const& shape, Attributes const&...attributes) const noexcept
283 {
284 return draw_box(layout, make_quad(shape), draw_attributes{attributes...});
285 }
286
293 void draw_line(widget_layout const& layout, line_segment const& line, draw_attributes const& attributes) const noexcept
294 {
295 hilet box = make_rectangle(line, attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
296
297 auto box_attributes = attributes;
298 box_attributes.line_width = 0.0f;
299 box_attributes.corner_radius =
300 make_corner_radii(attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
301 return draw_box(layout, box, box_attributes);
302 }
303
310 template<draw_attribute... Attributes>
311 void draw_line(widget_layout const& layout, line_segment const& line, Attributes const&...attributes) const noexcept
312 {
313 return draw_line(layout, line, draw_attributes{attributes...});
314 }
315
322 void draw_circle(widget_layout const& layout, hi::circle const& circle, draw_attributes const& attributes) const noexcept
323 {
324 auto box_attributes = attributes;
325 box_attributes.corner_radius = make_corner_radii(circle);
326 return draw_box(layout, make_rectangle(circle), box_attributes);
327 }
328
335 template<draw_attribute... Attributes>
336 void draw_circle(widget_layout const& layout, hi::circle const& circle, Attributes const&...attributes) const noexcept
337 {
338 return draw_circle(layout, circle, draw_attributes{attributes...});
339 }
340
350 [[nodiscard]] bool
351 draw_image(widget_layout const& layout, quad const& box, paged_image& image, draw_attributes const& attributes) const noexcept
352 {
353 return _draw_image(layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, image);
354 }
355
365 template<draw_attribute... Attributes>
366 [[nodiscard]] bool
367 draw_image(widget_layout const& layout, draw_quad_shape auto const& box, paged_image& image, Attributes const&...attributes)
368 const noexcept
369 {
370 return draw_image(layout, make_quad(box), image, draw_attributes{attributes...});
371 }
372
380 void draw_glyph(widget_layout const& layout, quad const& box, glyph_ids const& glyph, draw_attributes const& attributes)
381 const noexcept
382 {
383 return _draw_glyph(
384 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, glyph, attributes);
385 }
386
394 template<draw_quad_shape Shape, draw_attribute... Attributes>
395 void draw_glyph(widget_layout const& layout, Shape const& box, glyph_ids const& glyph, Attributes const&...attributes)
396 const noexcept
397 {
398 return draw_glyph(layout, make_quad(box), glyph, draw_attributes{attributes...});
399 }
400
408 void
409 draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, draw_attributes const& attributes)
410 const noexcept
411 {
412 return _draw_text(
413 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
414 layout.to_window3() * transform,
415 text,
416 attributes);
417 }
418
426 template<draw_attribute... Attributes>
427 void draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, Attributes const&...attributes)
428 const noexcept
429 {
430 return draw_text(layout, transform, text, draw_attributes{attributes...});
431 }
432
439 template<draw_attribute... Attributes>
440 void draw_text(widget_layout const& layout, text_shaper const& text, Attributes const&...attributes) const noexcept
441 {
442 return draw_text(layout, geo::identity{}, text, draw_attributes{attributes...});
443 }
444
453 widget_layout const& layout,
454 text_shaper const& text,
455 text_selection const& selection,
456 draw_attributes const& attributes) const noexcept
457 {
458 return _draw_text_selection(
459 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3(), text, selection, attributes);
460 }
461
469 template<draw_attribute... Attributes>
471 widget_layout const& layout,
472 text_shaper const& text,
473 text_selection const& selection,
474 Attributes const&...attributes) const noexcept
475 {
476 return draw_text_selection(layout, text, selection, draw_attributes{attributes...});
477 }
478
489 widget_layout const& layout,
490 text_shaper const& text,
491 text_cursor cursor,
492 bool overwrite_mode,
493 bool dead_character_mode,
494 draw_attributes const& attributes) const noexcept
495 {
496 return _draw_text_cursors(
497 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
498 layout.to_window3(),
499 text,
500 cursor,
501 overwrite_mode,
502 dead_character_mode,
503 attributes);
504 }
505
515 template<draw_attribute... Attributes>
517 widget_layout const& layout,
518 text_shaper const& text,
519 text_cursor cursor,
520 bool overwrite_mode,
521 bool dead_character_mode,
522 Attributes const&...attributes) const noexcept
523 {
524 return draw_text_cursors(layout, text, cursor, overwrite_mode, dead_character_mode, draw_attributes{attributes...});
525 }
526
536 void draw_hole(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
537 {
538 return _override_alpha(
539 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
540 }
541
551 template<draw_quad_shape Shape, draw_attribute... Attributes>
552 void draw_hole(widget_layout const& layout, Shape const& box, Attributes const&...attributes) const noexcept
553 {
554 return draw_hole(layout, make_quad(box), draw_attributes{attributes...});
555 }
556
564 [[nodiscard]] friend bool overlaps(draw_context const& context, widget_layout const& layout) noexcept
565 {
566 return overlaps(context.scissor_rectangle, layout.clipping_rectangle_on_window());
567 }
568
569private:
570 vector_span<pipeline_box::vertex> *_box_vertices;
571 vector_span<pipeline_image::vertex> *_image_vertices;
572 vector_span<pipeline_SDF::vertex> *_sdf_vertices;
573 vector_span<pipeline_alpha::vertex> *_alpha_vertices;
574
575 template<draw_quad_shape Shape>
576 [[nodiscard]] constexpr static quad make_quad(Shape const& shape) noexcept
577 {
578 if constexpr (std::is_same_v<Shape, aarectanglei>) {
579 return narrow_cast<aarectangle>(shape);
580 } else {
581 return shape;
582 }
583 }
584
585 [[nodiscard]] constexpr static rectangle
586 make_rectangle(line_segment const& line, float width, line_end_cap c1, line_end_cap c2) noexcept
587 {
588 auto right = line.direction();
589
590 hilet radius = width * 0.5f;
591 hilet n = normal(right, 0.0f);
592 hilet up = n * width;
593 hilet t = normalize(right);
594
595 auto origin = line.origin() - n * radius;
596
597 // Extend the line by the radius for rounded end-caps.
598 hilet radius_offset = t * radius;
599 if (c1 == line_end_cap::round) {
600 origin -= radius_offset;
601 right += radius_offset;
602 }
603 if (c2 == line_end_cap::round) {
604 right += radius_offset;
605 }
606
607 return rectangle{origin, right, up};
608 }
609
610 [[nodiscard]] constexpr static rectangle make_rectangle(hi::circle const& circle) noexcept
611 {
612 hilet circle_ = f32x4{circle};
613 hilet origin = point3{circle_.xyz1() - circle_.ww00()};
614 hilet right = vector3{circle_.w000() * 2.0f};
615 hilet up = vector3{circle_._0w00() * 2.0f};
616 return rectangle{origin, right, up};
617 }
618
619 [[nodiscard]] constexpr static corner_radii make_corner_radii(float width, line_end_cap c1, line_end_cap c2) noexcept
620 {
621 auto r = f32x4::broadcast(width * 0.5f);
622
623 if (c1 == line_end_cap::flat) {
624 r = set_zero<0b0101>(r);
625 }
626 if (c2 == line_end_cap::flat) {
627 r = set_zero<0b1010>(r);
628 }
629
630 return corner_radii{r};
631 }
632
633 [[nodiscard]] constexpr static corner_radii make_corner_radii(hi::circle const& circle) noexcept
634 {
635 return corner_radii{f32x4{circle}.wwww()};
636 }
637
638 void _override_alpha(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
639
640 void _draw_box(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
641
642 void _draw_text(
643 aarectanglei const& clipping_rectangle,
644 matrix3 const& transform,
645 text_shaper const& text,
646 draw_attributes const& attributes) const noexcept;
647
648 void _draw_text_selection(
649 aarectanglei const& clipping_rectangle,
650 matrix3 const& transform,
651 text_shaper const& text,
652 text_selection const& selection,
653 draw_attributes const& attributes) const noexcept;
654
655 void _draw_text_insertion_cursor_empty(
656 aarectanglei const& clipping_rectangle,
657 matrix3 const& transform,
658 text_shaper const& text,
659 draw_attributes const& attributes) const noexcept;
660
661 void _draw_text_insertion_cursor(
662 aarectanglei const& clipping_rectangle,
663 matrix3 const& transform,
664 text_shaper const& text,
665 text_cursor cursor,
666 bool show_flag,
667 draw_attributes const& attributes) const noexcept;
668
669 void _draw_text_overwrite_cursor(
670 aarectanglei const& clipping_rectangle,
671 matrix3 const& transform,
672 text_shaper::char_const_iterator it,
673 draw_attributes const& attributes) const noexcept;
674
675 void _draw_text_cursors(
676 aarectanglei const& clipping_rectangle,
677 matrix3 const& transform,
678 text_shaper const& text,
679 text_cursor cursor,
680 bool overwrite_mode,
681 bool dead_character_mode,
682 draw_attributes const& attributes) const noexcept;
683
684 void _draw_glyph(
685 aarectanglei const& clipping_rectangle,
686 quad const& box,
687 glyph_ids const& glyph,
688 draw_attributes const& attributes) const noexcept;
689
690 [[nodiscard]] bool _draw_image(aarectanglei const& clipping_rectangle, quad const& box, paged_image const& image) const noexcept;
691};
692
693}} // namespace hi::v1
Defines widget_layout.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:308
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:184
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
line_end_cap
The way two lines should be joined.
Definition line_end_cap.hpp:17
@ flat
The end cap of the line is flat.
@ round
The end cap of the line is round.
@ rectangle
The gui_event has rectangle data.
DOXYGEN BUG.
Definition algorithm.hpp:13
@ circle
<circle> Encircled form.
geometry/margins.hpp
Definition cache.hpp:11
border_side
The side where the border is drawn.
Definition draw_context.hpp:30
@ 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.
geo::matrix< 3 > matrix3
A 3D homogenious transformation matrix.
Definition matrix.hpp:599
This is a RGBA floating point color.
Definition color.hpp:42
A color for each corner of a quad.
Definition quad_color.hpp:19
static constexpr axis_aligned_rectangle large() noexcept
Create a large axis aligned rectangle.
Definition axis_aligned_rectangle.hpp:39
A type defining a 2D circle.
Definition circle.hpp:18
The 4 radii of the corners of a quad or rectangle.
Definition corner_radii.hpp:18
Identity transform.
Definition identity.hpp:20
Line segment.
Definition line_segment.hpp:19
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix.hpp:33
The draw attributes used to draw shaped into the draw context.
Definition draw_context.hpp:51
hi::border_side border_side
The side on which side of the edge of a shape the border should be drawn.
Definition draw_context.hpp:74
aarectanglei clipping_rectangle
The rectangle used the clip the shape when drawing.
Definition draw_context.hpp:85
float line_width
The width of a line, or the width of a border.
Definition draw_context.hpp:70
line_end_cap end_line_cap
The shape of the beginning of a line.
Definition draw_context.hpp:93
quad_color fill_color
The fill color used for the color of a box inside the border.
Definition draw_context.hpp:60
quad_color line_color
The line color used for the color of the border of the box.
Definition draw_context.hpp:66
line_end_cap begin_line_cap
The shape of the beginning of a line.
Definition draw_context.hpp:89
hi::corner_radii corner_radius
The radii of each corner of a quad.
Definition draw_context.hpp:78
Draw context for drawing using the HikoGUI shaders.
Definition draw_context.hpp:211
void draw_line(widget_layout const &layout, line_segment const &line, draw_attributes const &attributes) const noexcept
Draw a line.
Definition draw_context.hpp:293
void draw_circle(widget_layout const &layout, hi::circle const &circle, draw_attributes const &attributes) const noexcept
Draw a circle.
Definition draw_context.hpp:322
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:427
void draw_box(widget_layout const &layout, quad const &box, draw_attributes const &attributes) const noexcept
Draw a box.
Definition draw_context.hpp:269
hi::subpixel_orientation subpixel_orientation
The subpixel orientation for rendering glyphs.
Definition draw_context.hpp:229
void draw_circle(widget_layout const &layout, hi::circle const &circle, Attributes const &...attributes) const noexcept
Draw a circle.
Definition draw_context.hpp:336
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:395
void draw_text(widget_layout const &layout, text_shaper const &text, Attributes const &...attributes) const noexcept
Draw shaped text.
Definition draw_context.hpp:440
aarectanglei scissor_rectangle
This is the rectangle of the window that is being redrawn.
Definition draw_context.hpp:221
float saturation
The tone-mapper's saturation.
Definition draw_context.hpp:237
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:536
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:452
bool active
Window is active.
Definition draw_context.hpp:233
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:516
friend bool overlaps(draw_context const &context, widget_layout const &layout) noexcept
Checks if a widget's layout overlaps with the part of the window that is being drawn.
Definition draw_context.hpp:564
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:351
void draw_line(widget_layout const &layout, line_segment const &line, Attributes const &...attributes) const noexcept
Draw a line.
Definition draw_context.hpp:311
std::size_t frame_buffer_index
The frame buffer index of the image we are currently rendering.
Definition draw_context.hpp:217
void draw_box(widget_layout const &layout, Shape const &shape, Attributes const &...attributes) const noexcept
Draw a box.
Definition draw_context.hpp:282
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:488
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:409
color background_color
The background color to clear the window with.
Definition draw_context.hpp:225
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:367
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:552
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:470
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:380
utc_nanoseconds display_time_point
The time when the drawing will appear on the screen.
Definition draw_context.hpp:241
The layout of a widget.
Definition widget_layout.hpp:38
Definition draw_context.hpp:45
Definition draw_context.hpp:206
T right(T... args)
T max(T... args)