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/axis_aligned_rectangle.hpp"
13#include "../geometry/matrix.hpp"
14#include "../geometry/corner_radii.hpp"
15#include "../geometry/identity.hpp"
16#include "../geometry/transform.hpp"
17#include "../geometry/circle.hpp"
18#include "../geometry/line_end_cap.hpp"
19#include "../text/text_cursor.hpp"
20#include "../text/text_selection.hpp"
21#include "../text/text_shaper.hpp"
22#include "../color/color.hpp"
23#include "../color/quad_color.hpp"
25#include "../vector_span.hpp"
26
27namespace hi::inline v1 {
28class gfx_device;
29class gfx_device_vulkan;
30class shaped_text;
31class glyph_ids;
32struct paged_image;
33
36enum class border_side {
39 on,
40
43 inside,
44
48};
49
53public:
54 gfx_device_vulkan& device;
55
59
63
67
70 hi::subpixel_orientation subpixel_orientation;
71
74 bool active;
75
79
82 utc_nanoseconds display_time_point;
83
84 draw_context(draw_context const& rhs) noexcept = default;
85 draw_context(draw_context&& rhs) noexcept = default;
86 draw_context& operator=(draw_context const& rhs) noexcept = default;
87 draw_context& operator=(draw_context&& rhs) noexcept = default;
88 ~draw_context() = default;
89
91 gfx_device_vulkan& device,
95 vector_span<pipeline_alpha::vertex>& alpha_vertices) noexcept;
96
99 operator bool() const noexcept
100 {
101 return frame_buffer_index != std::numeric_limits<size_t>::max();
102 }
103
115 widget_layout const& layout,
116 quad const& box,
117 quad_color const& fill_color,
118 quad_color const& border_color,
119 float border_width,
120 hi::border_side border_side,
121 hi::corner_radii const& corner_radius = {}) const noexcept
122 {
123 // clang-format off
124 hilet border_radius = border_width * 0.5f;
125 hilet box_ =
126 border_side == hi::border_side::inside ? box - border_radius :
127 border_side == hi::border_side::outside ? box + border_radius :
128 box;
129 hilet corner_radius_ =
130 border_side == hi::border_side::inside ? corner_radius - border_radius :
131 border_side == hi::border_side::outside ? corner_radius + border_radius :
132 corner_radius;
133 // clang-format on
134
135 return _draw_box(
136 layout.clipping_rectangle_on_window(),
137 layout.to_window * box_,
138 fill_color,
139 border_color,
140 layout.to_window * border_width,
141 layout.to_window * corner_radius_);
142 }
143
156 widget_layout const& layout,
157 aarectangle const& clipping_rectangle,
158 quad const& box,
159 quad_color const& fill_color,
160 quad_color const& border_color,
161 float border_width,
162 hi::border_side border_side,
163 hi::corner_radii const& corner_radius = {}) const noexcept
164 {
165 // clang-format off
166 hilet border_radius = border_width * 0.5f;
167 hilet box_ =
168 border_side == hi::border_side::inside ? box - border_radius :
169 border_side == hi::border_side::outside ? box + border_radius :
170 box;
171 hilet corner_radius_ =
172 border_side == hi::border_side::inside ? corner_radius - border_radius :
173 border_side == hi::border_side::outside ? corner_radius + border_radius :
174 corner_radius;
175 // clang-format on
176
177 return _draw_box(
178 layout.clipping_rectangle_on_window(clipping_rectangle),
179 layout.to_window * box_,
180 fill_color,
181 border_color,
182 layout.to_window * border_width,
183 layout.to_window * corner_radius_);
184 }
193 widget_layout const& layout,
194 quad const& box,
195 quad_color const& fill_color,
196 hi::corner_radii const& corner_radius = {}) const noexcept
197 {
198 return _draw_box(
199 layout.clipping_rectangle_on_window(),
200 layout.to_window * box,
201 fill_color,
202 fill_color,
203 0.0f,
204 layout.to_window * corner_radius);
205 }
206
216 widget_layout const& layout,
217 aarectangle const& clipping_rectangle,
218 quad const& box,
219 quad_color const& fill_color,
220 hi::corner_radii const& corner_radius = {}) const noexcept
221 {
222 return _draw_box(
223 layout.clipping_rectangle_on_window(clipping_rectangle),
224 layout.to_window * box,
225 fill_color,
226 fill_color,
227 0.0f,
228 layout.to_window * corner_radius);
229 }
230
231 [[nodiscard]] constexpr static rectangle
232 make_rectangle(line_segment const& line, float width, line_end_cap c1, line_end_cap c2) noexcept
233 {
234 auto right = line.direction();
235
236 hilet radius = width * 0.5f;
237 hilet n = normal(right, 0.0f);
238 hilet up = n * width;
239 hilet t = normalize(right);
240
241 auto origin = line.origin() - n * radius;
242
243 // Extend the line by the radius for rounded end-caps.
244 hilet radius_offset = t * radius;
245 if (c1 == line_end_cap::round) {
246 origin -= radius_offset;
247 right += radius_offset;
248 }
249 if (c2 == line_end_cap::round) {
250 right += radius_offset;
251 }
252
253 return rectangle{origin, right, up};
254 }
255
256 [[nodiscard]] constexpr static corner_radii make_corner_radii(float width, line_end_cap c1, line_end_cap c2) noexcept
257 {
258 auto r = f32x4::broadcast(width * 0.5f);
259
260 if (c1 == line_end_cap::flat) {
261 r = zero<0b0101>(r);
262 }
263 if (c2 == line_end_cap::flat) {
264 r = zero<0b1010>(r);
265 }
266
267 return corner_radii{r};
268 }
269
270 void draw_line(
271 widget_layout const& layout,
272 line_segment const& line,
273 float width,
274 quad_color const& fill_color,
275 line_end_cap c1 = line_end_cap::flat,
276 line_end_cap c2 = line_end_cap::flat) const noexcept
277 {
278 hilet line_ = layout.to_window * line;
279 hilet width_ = layout.to_window * width;
280
281 hilet box = make_rectangle(line_, width_, c1, c2);
282 hilet corners = make_corner_radii(width_, c1, c2);
283
284 return _draw_box(layout.clipping_rectangle_on_window(), box, fill_color, fill_color, 0.0f, corners);
285 }
286
287 void draw_line(
288 widget_layout const& layout,
289 aarectangle const& clipping_rectangle,
290 line_segment const& line,
291 float width,
292 quad_color const& fill_color,
293 line_end_cap c1 = line_end_cap::flat,
294 line_end_cap c2 = line_end_cap::flat) const noexcept
295 {
296 hi_assert(width != 0.0f);
297 hilet line_ = layout.to_window * line;
298 hilet width_ = layout.to_window * width;
299
300 hilet box = make_rectangle(line_, width_, c1, c2);
301 hilet corners = make_corner_radii(width_, c1, c2);
302
303 return _draw_box(layout.clipping_rectangle_on_window(clipping_rectangle), box, fill_color, fill_color, 0.0f, corners);
304 }
305
306 [[nodiscard]] constexpr static rectangle make_rectangle(hi::circle const& circle) noexcept
307 {
308 hilet circle_ = f32x4{circle};
309 hilet origin = point3{circle_.xyz1() - circle_.ww00()};
310 hilet right = vector3{circle_.w000() * 2.0f};
311 hilet up = vector3{circle_._0w00() * 2.0f};
312 return rectangle{origin, right, up};
313 }
314
315 [[nodiscard]] constexpr static corner_radii make_corner_radii(hi::circle const& circle) noexcept
316 {
317 return corner_radii{f32x4{circle}.wwww()};
318 }
319
320 void draw_circle(widget_layout const& layout, hi::circle const& circle, quad_color const& fill_color) const noexcept
321 {
322 hilet box = layout.to_window * make_rectangle(circle);
323 hilet corners = layout.to_window * make_corner_radii(circle);
324 return _draw_box(layout.clipping_rectangle_on_window(), box, fill_color, fill_color, 0.0f, corners);
325 }
326
327 void draw_circle(
328 widget_layout const& layout,
329 aarectangle const clipping_rectangle,
330 hi::circle const& circle,
331 quad_color const& fill_color) const
332 {
333 hilet box = layout.to_window * make_rectangle(circle);
334 hilet corners = layout.to_window * make_corner_radii(circle);
335 return _draw_box(layout.clipping_rectangle_on_window(clipping_rectangle), box, fill_color, fill_color, 0.0f, corners);
336 }
337
338 void draw_circle(
339 widget_layout const& layout,
340 hi::circle const& circle,
341 quad_color const& fill_color,
342 quad_color const& border_color,
343 float border_width,
344 hi::border_side border_side) const noexcept
345 {
346 // clang-format off
347 hilet circle_ =
348 border_side == hi::border_side::inside ? circle - border_width * 0.5f :
349 border_side == hi::border_side::outside ? circle + border_width * 0.5f :
350 circle;
351 // clang-format on
352
353 hilet box = layout.to_window * make_rectangle(circle_);
354 hilet corners = layout.to_window * make_corner_radii(circle_);
355 return _draw_box(layout.clipping_rectangle_on_window(), box, fill_color, border_color, border_width, corners);
356 }
357
358 void draw_circle(
359 widget_layout const& layout,
360 aarectangle const& clipping_rectangle,
361 hi::circle const& circle,
362 quad_color const& fill_color,
363 quad_color const& border_color,
364 float border_width,
365 hi::border_side border_side) const noexcept
366 {
367 // clang-format off
368 hilet circle_ =
369 border_side == hi::border_side::inside ? circle - border_width * 0.5f :
370 border_side == hi::border_side::outside ? circle + border_width * 0.5f :
371 circle;
372 // clang-format on
373
374 hilet box = layout.to_window * make_rectangle(circle_);
375 hilet corners = layout.to_window * make_corner_radii(circle_);
376 return _draw_box(
377 layout.clipping_rectangle_on_window(clipping_rectangle), box, fill_color, border_color, border_width, corners);
378 }
379
388 [[nodiscard]] bool draw_image(widget_layout const& layout, quad const& box, paged_image& image) const noexcept
389 {
390 return _draw_image(layout.clipping_rectangle_on_window(), layout.to_window * box, image);
391 }
392
402 [[nodiscard]] bool
403 draw_image(widget_layout const& layout, aarectangle const& clipping_rectangle, quad const& box, paged_image& image)
404 const noexcept
405 {
406 return _draw_image(layout.clipping_rectangle_on_window(clipping_rectangle), layout.to_window * box, image);
407 }
408
416 void draw_glyph(widget_layout const& layout, quad const& box, quad_color const& color, glyph_ids const& glyph) const noexcept
417 {
418 return _draw_glyph(layout.clipping_rectangle_on_window(), layout.to_window * box, color, glyph);
419 }
420
430 widget_layout const& layout,
431 aarectangle clipping_rectangle,
432 quad const& box,
433 quad_color const& color,
434 glyph_ids const& glyph) const noexcept
435 {
436 return _draw_glyph(layout.clipping_rectangle_on_window(clipping_rectangle), layout.to_window * box, color, glyph);
437 }
438
446 void draw_text(widget_layout const& layout, matrix3 const& transform, quad_color const& color, shaped_text const& text)
447 const noexcept
448 {
449 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window * transform, text, color);
450 }
451
461 widget_layout const& layout,
462 aarectangle const& clipping_rectangle,
463 matrix3 const& transform,
464 quad_color const& color,
465 shaped_text const& text) const noexcept
466 {
467 return _draw_text(layout.clipping_rectangle_on_window(clipping_rectangle), layout.to_window * transform, text, color);
468 }
469
476 void draw_text(widget_layout const& layout, matrix3 const& transform, shaped_text const& text) const noexcept
477 {
478 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window * transform, text);
479 }
480
488 void draw_text(widget_layout const& layout, matrix3 const& transform, quad_color const& color, text_shaper const& text)
489 const noexcept
490 {
491 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window * transform, text, color);
492 }
493
500 void draw_text(widget_layout const& layout, quad_color const& color, text_shaper const& text) const noexcept
501 {
502 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window, text, color);
503 }
504
514 widget_layout const& layout,
515 aarectangle const& clipping_rectangle,
516 matrix3 const& transform,
517 quad_color const& color,
518 text_shaper const& text) const noexcept
519 {
520 return _draw_text(layout.clipping_rectangle_on_window(clipping_rectangle), layout.to_window * transform, text, color);
521 }
522
531 widget_layout const& layout,
532 aarectangle const& clipping_rectangle,
533 quad_color const& color,
534 text_shaper const& text) const noexcept
535 {
536 return _draw_text(layout.clipping_rectangle_on_window(clipping_rectangle), layout.to_window, text, color);
537 }
538
545 void draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text) const noexcept
546 {
547 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window * transform, text);
548 }
549
555 void draw_text(widget_layout const& layout, text_shaper const& text) const noexcept
556 {
557 return _draw_text(layout.clipping_rectangle_on_window(), layout.to_window, text);
558 }
559
567 void
568 draw_text_selection(widget_layout const& layout, text_shaper const& text, text_selection const& selection, hi::color color)
569 const noexcept
570 {
571 return _draw_text_selection(layout.clipping_rectangle_on_window(), layout.to_window, text, selection, color);
572 }
573
585 widget_layout const& layout,
586 text_shaper const& text,
587 text_cursor cursor,
588 hi::color primary_color,
589 hi::color secondary_color,
590 bool overwrite_mode,
591 bool dead_character_mode) const noexcept
592 {
593 return _draw_text_cursors(
594 layout.clipping_rectangle_on_window(),
595 layout.to_window,
596 text,
597 cursor,
598 primary_color,
599 secondary_color,
600 overwrite_mode,
601 dead_character_mode);
602 }
603
612 void make_hole(widget_layout const& layout, quad const& box) const noexcept
613 {
614 return _override_alpha(layout.clipping_rectangle_on_window(), layout.to_window * box, 0.0f);
615 }
616
617 [[nodiscard]] friend bool overlaps(draw_context const& context, widget_layout const& layout) noexcept
618 {
619 return overlaps(context.scissor_rectangle, layout.clipping_rectangle_on_window());
620 }
621
622private:
623 vector_span<pipeline_box::vertex> *_box_vertices;
624 vector_span<pipeline_image::vertex> *_image_vertices;
625 vector_span<pipeline_SDF::vertex> *_sdf_vertices;
626 vector_span<pipeline_alpha::vertex> *_alpha_vertices;
627
628 void _override_alpha(aarectangle const& clipping_rectangle, quad box, float alpha) const noexcept;
629
630 void _draw_box(
631 aarectangle const& clipping_rectangle,
632 quad box,
633 quad_color const& fill_color,
634 quad_color const& border_color,
635 float border_width,
636 hi::corner_radii corner_radius) const noexcept;
637
638 void _draw_text(
639 aarectangle const& clipping_rectangle,
640 matrix3 const& transform,
641 shaped_text const& text,
642 std::optional<quad_color> color = {}) const noexcept;
643
644 void _draw_text(
645 aarectangle const& clipping_rectangle,
646 matrix3 const& transform,
647 text_shaper const& text,
648 std::optional<quad_color> color = {}) const noexcept;
649
650 void _draw_text_selection(
651 aarectangle const& clipping_rectangle,
652 matrix3 const& transform,
653 text_shaper const& text,
654 text_selection const& selection,
655 hi::color) const noexcept;
656
657 void _draw_text_insertion_cursor_empty(
658 aarectangle const& clipping_rectangle,
659 matrix3 const& transform,
660 text_shaper const& text,
661 hi::color color) const noexcept;
662
663 void _draw_text_insertion_cursor(
664 aarectangle const& clipping_rectangle,
665 matrix3 const& transform,
666 text_shaper const& text,
667 text_cursor cursor,
668 hi::color color,
669 bool show_flag) const noexcept;
670
671 void _draw_text_overwrite_cursor(
672 aarectangle const& clipping_rectangle,
673 matrix3 const& transform,
674 text_shaper::char_const_iterator it,
675 hi::color color) const noexcept;
676
677 void _draw_text_cursors(
678 aarectangle const& clipping_rectangle,
679 matrix3 const& transform,
680 text_shaper const& text,
681 text_cursor cursor,
682 hi::color primary_color,
683 hi::color secondary_color,
684 bool overwrite_mode,
685 bool dead_character_mode) const noexcept;
686
687 void _draw_glyph(aarectangle const& clipping_rectangle, quad const& box, quad_color const& color, glyph_ids const& glyph)
688 const noexcept;
689
690 [[nodiscard]] bool _draw_image(aarectangle const& clipping_rectangle, quad const& box, paged_image& image) const noexcept;
691};
692
693} // namespace hi::inline v1
#define hi_assert(expression)
Assert if expression is true.
Definition assert.hpp:86
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
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:36
@ 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
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:20
Definition quad.hpp:17
Draw context for drawing using the HikoGUI shaders.
Definition draw_context.hpp:52
std::size_t frame_buffer_index
The frame buffer index of the image we are currently rendering.
Definition draw_context.hpp:58
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:545
void draw_box(widget_layout const &layout, quad const &box, quad_color const &fill_color, hi::corner_radii const &corner_radius={}) const noexcept
Draw a box with rounded corners without a border.
Definition draw_context.hpp:192
float saturation
The tone-mapper's saturation.
Definition draw_context.hpp:78
utc_nanoseconds display_time_point
The time when the drawing will appear on the screen.
Definition draw_context.hpp:82
aarectangle scissor_rectangle
This is the rectangle of the window that is being redrawn.
Definition draw_context.hpp:62
void draw_text(widget_layout const &layout, aarectangle const &clipping_rectangle, matrix3 const &transform, quad_color const &color, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:513
void draw_text(widget_layout const &layout, matrix3 const &transform, shaped_text const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:476
bool draw_image(widget_layout const &layout, aarectangle const &clipping_rectangle, quad const &box, paged_image &image) const noexcept
Draw an image.
Definition draw_context.hpp:403
void draw_text_cursors(widget_layout const &layout, text_shaper const &text, text_cursor cursor, hi::color primary_color, hi::color secondary_color, bool overwrite_mode, bool dead_character_mode) const noexcept
Draw text cursors of shaped text.
Definition draw_context.hpp:584
void draw_text(widget_layout const &layout, quad_color const &color, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:500
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, hi::color color) const noexcept
Draw text-selection of shaped text.
Definition draw_context.hpp:568
color background_color
The background color to clear the window with.
Definition draw_context.hpp:66
void draw_glyph(widget_layout const &layout, aarectangle clipping_rectangle, quad const &box, quad_color const &color, glyph_ids const &glyph) const noexcept
Draw a glyph.
Definition draw_context.hpp:429
void draw_text(widget_layout const &layout, matrix3 const &transform, quad_color const &color, shaped_text const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:446
void draw_box(widget_layout const &layout, aarectangle const &clipping_rectangle, quad const &box, quad_color const &fill_color, hi::corner_radii const &corner_radius={}) const noexcept
Draw a box with rounded corners without a border.
Definition draw_context.hpp:215
void make_hole(widget_layout const &layout, quad const &box) const noexcept
Make a hole in the user interface.
Definition draw_context.hpp:612
void draw_glyph(widget_layout const &layout, quad const &box, quad_color const &color, glyph_ids const &glyph) const noexcept
Draw a glyph.
Definition draw_context.hpp:416
void draw_text(widget_layout const &layout, matrix3 const &transform, quad_color const &color, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:488
void draw_box(widget_layout const &layout, quad const &box, quad_color const &fill_color, quad_color const &border_color, float border_width, hi::border_side border_side, hi::corner_radii const &corner_radius={}) const noexcept
Draw a box with rounded corners.
Definition draw_context.hpp:114
void draw_text(widget_layout const &layout, aarectangle const &clipping_rectangle, quad_color const &color, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:530
void draw_text(widget_layout const &layout, aarectangle const &clipping_rectangle, matrix3 const &transform, quad_color const &color, shaped_text const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:460
hi::subpixel_orientation subpixel_orientation
The subpixel orientation for rendering glyphs.
Definition draw_context.hpp:70
void draw_box(widget_layout const &layout, aarectangle const &clipping_rectangle, quad const &box, quad_color const &fill_color, quad_color const &border_color, float border_width, hi::border_side border_side, hi::corner_radii const &corner_radius={}) const noexcept
Draw a box with rounded corners.
Definition draw_context.hpp:155
bool active
Window is active.
Definition draw_context.hpp:74
void draw_text(widget_layout const &layout, text_shaper const &text) const noexcept
Draw shaped text.
Definition draw_context.hpp:555
bool draw_image(widget_layout const &layout, quad const &box, paged_image &image) const noexcept
Draw an image.
Definition draw_context.hpp:388
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:39
Definition vector_span.hpp:134
T right(T... args)
T max(T... args)