7#include "draw_context_intf.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_override_vulkan_impl.hpp"
12#include "gfx_device_vulkan_intf.hpp"
13#include "../text/text.hpp"
14#include "../macros.hpp"
16hi_export_module(hikogui.GFX : draw_context_impl);
18hi_export
namespace hi {
inline namespace v1 {
20inline draw_context::draw_context(
22 vector_span<gfx_pipeline_box::vertex>& box_vertices,
23 vector_span<gfx_pipeline_image::vertex>& image_vertices,
24 vector_span<gfx_pipeline_SDF::vertex>& sdf_vertices,
25 vector_span<gfx_pipeline_override::vertex>& override_vertices) noexcept :
29 _box_vertices(&box_vertices),
30 _image_vertices(&image_vertices),
31 _sdf_vertices(&sdf_vertices),
32 _override_vertices(&override_vertices)
34 _box_vertices->clear();
35 _image_vertices->clear();
36 _sdf_vertices->clear();
37 _override_vertices->clear();
43 if (_override_vertices->full()) {
45 ++global_counter<
"override::overflow">;
49 gfx_pipeline_override::device_shared::place_vertices(*_override_vertices, clipping_rectangle, box, attributes.fill_color, attributes.line_color);
56 auto const border_radius = attributes.line_width * 0.5f;
58 attributes.border_side == hi::border_side::inside ? box - border_radius :
59 attributes.border_side == hi::border_side::outside ? box + border_radius :
62 auto const corner_radius =
63 attributes.border_side == hi::border_side::inside ? attributes.corner_radius - border_radius :
64 attributes.border_side == hi::border_side::outside ? attributes.corner_radius + border_radius :
65 attributes.corner_radius;
68 if (_box_vertices->full()) {
70 ++global_counter<
"draw_box::overflow">;
74 gfx_pipeline_box::device_shared::place_vertices(
78 attributes.fill_color,
79 attributes.line_color,
80 attributes.line_width,
84[[nodiscard]]
inline bool draw_context::_draw_image(
89 hi_assert_not_null(_image_vertices);
91 if (image.state != gfx_pipeline_image::paged_image::state_type::uploaded) {
95 device->image_pipeline->place_vertices(*_image_vertices, clipping_rectangle, box, image);
99inline void draw_context::_draw_glyph(
106 hi_assert_not_null(_sdf_vertices);
108 if (_sdf_vertices->full()) {
109 auto box_attributes = attributes;
110 box_attributes.fill_color = hi::color{1.0f, 0.0f, 1.0f};
111 _draw_box(clipping_rectangle, box, box_attributes);
112 ++global_counter<
"draw_glyph::overflow">;
116 auto const atlas_was_updated =
117 device->SDF_pipeline->place_vertices(*_sdf_vertices, clipping_rectangle, box,
font, glyph, attributes.fill_color);
119 if (atlas_was_updated) {
120 device->SDF_pipeline->prepare_atlas_for_rendering();
124inline void draw_context::_draw_text(
127 text_shaper
const& text,
130 hi_assert_not_null(_sdf_vertices);
132 auto atlas_was_updated =
false;
133 for (
auto const& c : text) {
134 auto const box =
translate2{c.position} * c.metrics.bounding_rectangle;
135 auto const color = attributes.num_colors > 0 ? attributes.fill_color :
quad_color{c.style.color()};
137 if (not is_visible(c.general_category)) {
140 }
else if (_sdf_vertices->full()) {
141 auto box_attributes = attributes;
142 box_attributes.fill_color = hi::color{1.0f, 0.0f, 1.0f};
143 _draw_box(clipping_rectangle, box, box_attributes);
144 ++global_counter<
"draw_glyph::overflow">;
148 atlas_was_updated |= device->SDF_pipeline->place_vertices(
149 *_sdf_vertices, clipping_rectangle, transform * box, *c.glyphs.font, c.glyphs.front(),
color);
152 if (atlas_was_updated) {
153 device->SDF_pipeline->prepare_atlas_for_rendering();
157inline void draw_context::_draw_text_selection(
160 text_shaper
const& text,
161 text_selection
const& selection,
164 auto const[first, last] = selection.selection_indices();
165 auto const first_ = text.begin() + first;
166 auto const last_ = text.begin() + last;
167 hi_axiom(first_ <= text.end());
168 hi_axiom(last_ <= text.end());
169 hi_axiom(first_ <= last_);
171 for (
auto it = first_; it != last_; ++it) {
172 _draw_box(clipping_rectangle, transform * it->rectangle, attributes);
176inline void draw_context::_draw_text_insertion_cursor_empty(
179 text_shaper
const& text,
182 auto const maximum_left =
std::round(text.rectangle().left() - 0.5f);
183 auto const maximum_right =
std::round(text.rectangle().right() - 0.5f);
184 auto const& only_line = text.lines()[0];
188 auto const left = only_line.paragraph_direction == unicode_bidi_class::L ? maximum_left : maximum_right;
191 _draw_box(clipping_rectangle, transform * shape_I, attributes);
194inline void draw_context::_draw_text_insertion_cursor(
197 text_shaper
const& text,
202 auto const maximum_left =
std::round(text.rectangle().left() - 0.5f);
203 auto const maximum_right =
std::round(text.rectangle().right() - 0.5f);
205 auto const it = text.get_it(cursor);
206 auto const& line = text.lines()[it->line_nr];
207 auto const ltr = it->direction == unicode_bidi_class::L;
208 auto const on_right = ltr == cursor.after();
213 auto left =
std::round((on_right ? it->rectangle.right() : it->rectangle.left()) - 0.5f);
215 auto const next_line_nr = it->line_nr + 1;
216 auto const line_ltr = line.paragraph_direction == unicode_bidi_class::L;
217 auto const end_of_line = line_ltr ? it->column_nr == line.columns.size() - 1 : it->column_nr == 0;
218 if (cursor.after() and end_of_line and next_line_nr < text.lines().size()) {
221 auto const& next_line = text.lines()[next_line_nr];
225 left = it->direction == unicode_bidi_class::L ? maximum_left : maximum_right;
229 left = std::clamp(
left, maximum_left - 1.0f, maximum_right + 1.0f);
233 _draw_box(clipping_rectangle, transform * shape_I, attributes);
240 _draw_box(clipping_rectangle, transform * shape_flag, attributes);
244inline void draw_context::_draw_text_overwrite_cursor(
247 text_shaper::char_const_iterator it,
250 auto const box =
ceil(it->rectangle) + 0.5f;
251 _draw_box(clipping_rectangle, transform * box, attributes);
254inline void draw_context::_draw_text_cursors(
257 text_shaper
const& text,
258 text_cursor primary_cursor,
260 bool dead_character_mode,
263 hi_axiom(attributes.line_width == 0.0f);
267 return _draw_text_insertion_cursor_empty(clipping_rectangle, transform, text, attributes);
270 auto draw_flags =
false;
272 hi_assert_bounds(primary_cursor.index(), text);
274 if (dead_character_mode) {
275 hi_assert(primary_cursor.before());
276 auto cursor_attributes = attributes;
277 cursor_attributes.fill_color = attributes.line_color;
278 cursor_attributes.line_color = {};
279 return _draw_text_overwrite_cursor(
280 clipping_rectangle, transform, text.begin() + primary_cursor.index(), cursor_attributes);
283 if (overwrite_mode and primary_cursor.before()) {
284 auto cursor_attributes = attributes;
285 cursor_attributes.fill_color = {};
286 cursor_attributes.line_color = attributes.fill_color;
287 cursor_attributes.line_width = 1.0f;
288 return _draw_text_overwrite_cursor(
289 clipping_rectangle, transform, text.begin() + primary_cursor.index(), cursor_attributes);
293 auto const primary_it = text.begin() + primary_cursor.index();
294 auto const primary_ltr = primary_it->direction == unicode_bidi_class::L;
295 auto const primary_is_on_right = primary_ltr == primary_cursor.after();
296 auto const primary_is_on_left = not primary_is_on_right;
299 if (primary_cursor.start_of_text() or primary_cursor.end_of_text(text.size())) {
304 auto const secondary_cursor = primary_cursor.neighbor(text.size());
305 auto const secondary_it = text.begin() + secondary_cursor.index();
306 auto const secondary_ltr = secondary_it->direction == unicode_bidi_class::L;
307 auto const secondary_is_on_right = secondary_ltr == secondary_cursor.after();
308 auto const secondary_is_on_left = not secondary_is_on_right;
310 if (primary_is_on_right and secondary_is_on_left and text.move_right_char(primary_it) == secondary_it) {
313 }
else if (primary_is_on_left and secondary_is_on_right and text.move_left_char(primary_it) == secondary_it) {
319 auto cursor_attributes = attributes;
320 cursor_attributes.fill_color = attributes.line_color;
321 cursor_attributes.line_color = {};
322 _draw_text_insertion_cursor(clipping_rectangle, transform, text, secondary_cursor, draw_flags, cursor_attributes);
325 _draw_text_insertion_cursor(clipping_rectangle, transform, text, primary_cursor, draw_flags, attributes);
@ bottom
Align to the bottom.
Definition alignment.hpp:40
@ top
Align to the top.
Definition alignment.hpp:32
@ left
Align the text to the left side.
Definition alignment.hpp:118
The HikoGUI namespace.
Definition array_generic.hpp:21
The HikoGUI API version 1.
Definition array_generic.hpp:22
@ font
A font or font-size has changed.
Definition style_modify_mask.hpp:47
This is a RGBA floating point color.
Definition color_intf.hpp:49
A color for each corner of a quad.
Definition quad_color.hpp:22
An identifier for a font-family that was registered with HikoGUI.
Definition font_id.hpp:23
The identifier of a glyph in a font-file.
Definition glyph_id.hpp:22
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix3.hpp:36
Definition translate2.hpp:18
The draw attributes used to draw shaped into the draw context.
Definition draw_context_intf.hpp:49
This is a image that is uploaded into the texture atlas.
Definition gfx_pipeline_image_vulkan_intf.hpp:83