7#include "draw_context.hpp"
8#include "gfx_pipeline_box_vulkan_impl.hpp"
9#include "gfx_pipeline_image_vulkan_impl.hpp"
10#include "gfx_pipeline_SDF_vulkan_impl.hpp"
11#include "gfx_pipeline_alpha_vulkan_impl.hpp"
12#include "gfx_device_vulkan.hpp"
13#include "../text/module.hpp"
14#include "../macros.hpp"
16namespace hi {
inline namespace v1 {
18inline draw_context::draw_context(
20 vector_span<gfx_pipeline_box::vertex>& box_vertices,
21 vector_span<gfx_pipeline_image::vertex>& image_vertices,
22 vector_span<gfx_pipeline_SDF::vertex>& sdf_vertices,
23 vector_span<gfx_pipeline_alpha::vertex>& alpha_vertices) noexcept :
27 _box_vertices(&box_vertices),
28 _image_vertices(&image_vertices),
29 _sdf_vertices(&sdf_vertices),
30 _alpha_vertices(&alpha_vertices)
32 _box_vertices->clear();
33 _image_vertices->clear();
34 _sdf_vertices->clear();
35 _alpha_vertices->clear();
39draw_context::_override_alpha(
aarectangle const& clipping_rectangle, quad box,
draw_attributes const& attributes)
const noexcept
41 if (_alpha_vertices->full()) {
43 ++global_counter<
"override_alpha::overflow">;
47 gfx_pipeline_alpha::device_shared::place_vertices(*_alpha_vertices, clipping_rectangle, box, attributes.fill_color.p0.a());
54 hilet border_radius = attributes.line_width * 0.5f;
56 attributes.border_side == hi::border_side::inside ? box - border_radius :
57 attributes.border_side == hi::border_side::outside ? box + border_radius :
61 attributes.border_side == hi::border_side::inside ? attributes.corner_radius - border_radius :
62 attributes.border_side == hi::border_side::outside ? attributes.corner_radius + border_radius :
63 attributes.corner_radius;
66 if (_box_vertices->full()) {
68 ++global_counter<
"draw_box::overflow">;
72 gfx_pipeline_box::device_shared::place_vertices(
76 attributes.fill_color,
77 attributes.line_color,
78 attributes.line_width,
82[[nodiscard]]
inline bool draw_context::_draw_image(
87 hi_assert_not_null(_image_vertices);
89 if (image.state != gfx_pipeline_image::paged_image::state_type::uploaded) {
93 device->image_pipeline->place_vertices(*_image_vertices, clipping_rectangle, box, image);
97inline void draw_context::_draw_glyph(
104 hi_assert_not_null(_sdf_vertices);
106 if (_sdf_vertices->full()) {
107 auto box_attributes = attributes;
108 box_attributes.fill_color = hi::color{1.0f, 0.0f, 1.0f};
109 _draw_box(clipping_rectangle, box, box_attributes);
110 ++global_counter<
"draw_glyph::overflow">;
114 hilet atlas_was_updated =
115 device->SDF_pipeline->place_vertices(*_sdf_vertices, clipping_rectangle, box, font, glyph, attributes.fill_color);
117 if (atlas_was_updated) {
118 device->SDF_pipeline->prepare_atlas_for_rendering();
122inline void draw_context::_draw_text(
125 text_shaper
const& text,
128 hi_assert_not_null(_sdf_vertices);
130 auto atlas_was_updated =
false;
131 for (hilet& c : text) {
132 hilet box =
translate2{c.position} * c.metrics.bounding_rectangle;
133 hilet
color = attributes.num_colors > 0 ? attributes.fill_color :
quad_color{c.style->color};
135 if (not is_visible(c.general_category)) {
138 }
else if (_sdf_vertices->full()) {
139 auto box_attributes = attributes;
140 box_attributes.fill_color = hi::color{1.0f, 0.0f, 1.0f};
141 _draw_box(clipping_rectangle, box, box_attributes);
142 ++global_counter<
"draw_glyph::overflow">;
146 atlas_was_updated |= device->SDF_pipeline->place_vertices(
147 *_sdf_vertices, clipping_rectangle, transform * box, *c.glyphs.font, c.glyphs.ids.front(),
color);
150 if (atlas_was_updated) {
151 device->SDF_pipeline->prepare_atlas_for_rendering();
155inline void draw_context::_draw_text_selection(
158 text_shaper
const& text,
159 text_selection
const& selection,
162 hilet[first, last] = selection.selection_indices();
163 hilet first_ = text.begin() + first;
164 hilet last_ = text.begin() + last;
165 hi_axiom(first_ <= text.end());
166 hi_axiom(last_ <= text.end());
167 hi_axiom(first_ <= last_);
169 for (
auto it = first_; it != last_; ++it) {
170 _draw_box(clipping_rectangle, transform * it->rectangle, attributes);
174inline void draw_context::_draw_text_insertion_cursor_empty(
177 text_shaper
const& text,
180 hilet maximum_left =
std::round(text.rectangle().left() - 0.5f);
181 hilet maximum_right =
std::round(text.rectangle().right() - 0.5f);
182 hilet& only_line = text.lines()[0];
186 hilet
left = only_line.paragraph_direction == unicode_bidi_class::L ? maximum_left : maximum_right;
189 _draw_box(clipping_rectangle, transform * shape_I, attributes);
192inline void draw_context::_draw_text_insertion_cursor(
195 text_shaper
const& text,
200 hilet maximum_left =
std::round(text.rectangle().left() - 0.5f);
201 hilet maximum_right =
std::round(text.rectangle().right() - 0.5f);
203 hilet it = text.get_it(cursor);
204 hilet& line = text.lines()[it->line_nr];
205 hilet ltr = it->direction == unicode_bidi_class::L;
206 hilet on_right = ltr == cursor.after();
211 auto left =
std::round((on_right ? it->rectangle.right() : it->rectangle.left()) - 0.5f);
213 hilet next_line_nr = it->line_nr + 1;
214 hilet line_ltr = line.paragraph_direction == unicode_bidi_class::L;
215 hilet end_of_line = line_ltr ? it->column_nr == line.columns.size() - 1 : it->column_nr == 0;
216 if (cursor.after() and end_of_line and next_line_nr < text.lines().size()) {
219 hilet& next_line = text.lines()[next_line_nr];
223 left = it->direction == unicode_bidi_class::L ? maximum_left : maximum_right;
227 left = std::clamp(
left, maximum_left - 1.0f, maximum_right + 1.0f);
231 _draw_box(clipping_rectangle, transform * shape_I, attributes);
238 _draw_box(clipping_rectangle, transform * shape_flag, attributes);
242inline void draw_context::_draw_text_overwrite_cursor(
245 text_shaper::char_const_iterator it,
248 hilet box =
ceil(it->rectangle) + 0.5f;
249 _draw_box(clipping_rectangle, transform * box, attributes);
252inline void draw_context::_draw_text_cursors(
255 text_shaper
const& text,
256 text_cursor primary_cursor,
258 bool dead_character_mode,
261 hi_axiom(attributes.line_width == 0.0f);
265 return _draw_text_insertion_cursor_empty(clipping_rectangle, transform, text, attributes);
268 auto draw_flags =
false;
270 hi_assert_bounds(primary_cursor.index(), text);
272 if (dead_character_mode) {
273 hi_assert(primary_cursor.before());
274 auto cursor_attributes = attributes;
275 cursor_attributes.fill_color = attributes.line_color;
276 cursor_attributes.line_color = {};
277 return _draw_text_overwrite_cursor(
278 clipping_rectangle, transform, text.begin() + primary_cursor.index(), cursor_attributes);
281 if (overwrite_mode and primary_cursor.before()) {
282 auto cursor_attributes = attributes;
283 cursor_attributes.fill_color = {};
284 cursor_attributes.line_color = attributes.fill_color;
285 cursor_attributes.line_width = 1.0f;
286 return _draw_text_overwrite_cursor(
287 clipping_rectangle, transform, text.begin() + primary_cursor.index(), cursor_attributes);
291 hilet primary_it = text.begin() + primary_cursor.index();
292 hilet primary_ltr = primary_it->direction == unicode_bidi_class::L;
293 hilet primary_is_on_right = primary_ltr == primary_cursor.after();
294 hilet primary_is_on_left = not primary_is_on_right;
297 if (primary_cursor.start_of_text() or primary_cursor.end_of_text(text.size())) {
302 hilet secondary_cursor = primary_cursor.neighbor(text.size());
303 hilet secondary_it = text.begin() + secondary_cursor.index();
304 hilet secondary_ltr = secondary_it->direction == unicode_bidi_class::L;
305 hilet secondary_is_on_right = secondary_ltr == secondary_cursor.after();
306 hilet secondary_is_on_left = not secondary_is_on_right;
308 if (primary_is_on_right and secondary_is_on_left and text.move_right_char(primary_it) == secondary_it) {
311 }
else if (primary_is_on_left and secondary_is_on_right and text.move_left_char(primary_it) == secondary_it) {
317 auto cursor_attributes = attributes;
318 cursor_attributes.fill_color = attributes.line_color;
319 cursor_attributes.line_color = {};
320 _draw_text_insertion_cursor(clipping_rectangle, transform, text, secondary_cursor, draw_flags, cursor_attributes);
323 _draw_text_insertion_cursor(clipping_rectangle, transform, text, primary_cursor, draw_flags, attributes);
@ bottom
Align to the bottom.
Definition alignment.hpp:37
@ top
Align to the top.
Definition alignment.hpp:29
@ left
Align the text to the left side.
Definition alignment.hpp:119
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
The HikoGUI API version 1.
Definition lookahead_iterator.hpp:6
This is a RGBA floating point color.
Definition color.hpp:45
A color for each corner of a quad.
Definition quad_color.hpp:20
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix3.hpp:30
Definition translate2.hpp:14
The draw attributes used to draw shaped into the draw context.
Definition draw_context.hpp:48
This is a image that is uploaded into the texture atlas.
Definition gfx_pipeline_image_vulkan.hpp:79