From 98bf39587fa49e095b19f6bf1ae549c231d1b208 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 10:40:42 +0300 Subject: [PATCH 01/52] demos/painter_path_test: can load many paths and cycle through them for viewing --- demos/common/command_line_list.hpp | 57 ++++ demos/painter_path_test/main.cpp | 447 ++++++++++++++++------------- 2 files changed, 308 insertions(+), 196 deletions(-) create mode 100644 demos/common/command_line_list.hpp diff --git a/demos/common/command_line_list.hpp b/demos/common/command_line_list.hpp new file mode 100644 index 000000000..c3b46c334 --- /dev/null +++ b/demos/common/command_line_list.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include "generic_command_line.hpp" + +template +class command_line_list: + public command_line_argument, + public std::set +{ +public: + command_line_list(const std::string &nm, + const std::string &desc, + command_line_register &p): + command_line_argument(p), + m_name(nm) + { + std::ostringstream ostr; + ostr << "\n\t" << m_name << " value" + << format_description_string(m_name, desc); + m_description = tabs_to_spaces(ostr.str()); + } + + virtual + int + check_arg(const std::vector &argv, int location) + { + int argc(argv.size()); + if (location + 1 < argc && argv[location] == m_name) + { + T v; + readvalue_from_string(v, argv[location + 1]); + this->insert(v); + std::cout << "\n\t" << m_name << " added: "; + writevalue_to_stream(v, std::cout); + return 2; + } + return 0; + } + + virtual + void + print_command_line_description(std::ostream &ostr) const + { + ostr << "[" << m_name << " value] "; + } + + virtual + void + print_detailed_description(std::ostream &ostr) const + { + ostr << m_description; + } + +private: + std::string m_name, m_description; +}; diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index 402d2d4e1..e83edd113 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -17,6 +17,7 @@ #include "cycle_value.hpp" #include "ostream_utility.hpp" #include "text_helper.hpp" +#include "command_line_list.hpp" using namespace fastuidraw; @@ -122,12 +123,25 @@ enable_wire_frame(bool b) #endif } +class PerPath +{ +public: + PerPath(const Path &path, const std::string &label, + int w, int h); + + Path m_path; + std::string m_label; + unsigned int m_fill_rule; + unsigned int m_end_fill_rule; + vec2 m_shear, m_shear2; + PanZoomTrackerSDLEvent m_path_zoomer; +}; + class painter_stroke_test:public sdl_painter_demo { public: painter_stroke_test(void); - protected: void @@ -164,10 +178,10 @@ class painter_stroke_test:public sdl_painter_demo reference_counted_ptr > named_color_stop; void - construct_path(void); + construct_paths(int w, int h); void - create_stroked_path_attributes(void); + per_path_processing(void); void construct_color_stops(void); @@ -184,11 +198,47 @@ class painter_stroke_test:public sdl_painter_demo void update_cts_params(void); + PanZoomTrackerSDLEvent& + zoomer(void) + { + return m_paths[m_selected_path].m_path_zoomer; + } + + Path& + path(void) + { + return m_paths[m_selected_path].m_path; + } + + unsigned int& + current_fill_rule(void) + { + return m_paths[m_selected_path].m_fill_rule; + } + + unsigned int + current_end_fill_rule(void) + { + return m_paths[m_selected_path].m_end_fill_rule; + } + + vec2& + shear(void) + { + return m_paths[m_selected_path].m_shear; + } + + vec2& + shear2(void) + { + return m_paths[m_selected_path].m_shear2; + } + command_line_argument_value m_change_miter_limit_rate; command_line_argument_value m_change_stroke_width_rate; command_line_argument_value m_window_change_rate; command_line_argument_value m_radial_gradient_change_rate; - command_line_argument_value m_path_file; + command_line_list m_path_file_list; DashPatternList m_dash_pattern_files; command_line_argument_value m_print_path; color_stop_arguments m_color_stop_args; @@ -197,8 +247,7 @@ class painter_stroke_test:public sdl_painter_demo command_line_argument_value m_sub_image_x, m_sub_image_y; command_line_argument_value m_sub_image_w, m_sub_image_h; command_line_argument_value m_font_file; - command_line_argument_value m_path_from_glyph; - command_line_argument_value m_character_code; + command_line_list m_character_code_list; command_line_argument_value m_stroke_red; command_line_argument_value m_stroke_green; command_line_argument_value m_stroke_blue; @@ -208,14 +257,13 @@ class painter_stroke_test:public sdl_painter_demo command_line_argument_value m_fill_blue; command_line_argument_value m_fill_alpha; - Path m_path; + std::vector m_paths; reference_counted_ptr m_image; uvec2 m_image_offset, m_image_size; std::vector m_color_stops; std::vector > m_dash_patterns; reference_counted_ptr m_font; - PanZoomTrackerSDLEvent m_zoomer; vecN m_gradient_mode_labels; vecN m_cap_labels; vecN m_join_labels; @@ -226,10 +274,11 @@ class painter_stroke_test:public sdl_painter_demo PainterPackedValue m_white_pen; PainterPackedValue m_stroke_pen; + unsigned int m_selected_path; unsigned int m_join_style; unsigned int m_cap_style; bool m_close_contour; - unsigned int m_fill_rule; + /* m_dash pattern: 0 -> undashed stroking [1, m_dash_patterns.size()] -> dashed stroking @@ -248,7 +297,6 @@ class painter_stroke_test:public sdl_painter_demo return m_dash - 1; } - unsigned int m_end_fill_rule; bool m_have_miter_limit; float m_miter_limit, m_stroke_width; bool m_draw_fill, m_aa_fill_by_stroking; @@ -273,11 +321,9 @@ class painter_stroke_test:public sdl_painter_demo bool m_with_aa; bool m_wire_frame; bool m_stroke_width_in_pixels; - bool m_stroke_width_pixels_scaled_by_zoom; bool m_force_square_viewport; bool m_fill_by_clipping; - vec2 m_shear, m_shear2; bool m_draw_grid; float m_angle; @@ -290,6 +336,38 @@ class painter_stroke_test:public sdl_painter_demo bool m_clip_window_path_dirty; }; +/////////////////////////////////// +// PerPath methods +PerPath:: +PerPath(const Path &path, const std::string &label, int w, int h): + m_path(path), + m_label(label), + m_fill_rule(PainterEnums::odd_even_fill_rule), + m_end_fill_rule(PainterEnums::fill_rule_data_count), + m_shear(1.0f, 1.0f), + m_shear2(1.0f, 1.0f) +{ + m_end_fill_rule = + m_path.tessellation()->filled()->subset(0).winding_numbers().size() + PainterEnums::fill_rule_data_count; + + /* set transformation to center and contain path. */ + vec2 p0, p1, delta, dsp(w, h), ratio, mid; + float mm; + p0 = m_path.tessellation()->bounding_box_min(); + p1 = m_path.tessellation()->bounding_box_max(); + + delta = p1 - p0; + ratio = delta / dsp; + mm = t_max(0.00001f, t_max(ratio.x(), ratio.y()) ); + mid = 0.5 * (p1 + p0); + + ScaleTranslate sc, tr1, tr2; + tr1.translation(-mid); + sc.scale( 1.0f / mm); + tr2.translation(dsp * 0.5f); + m_path_zoomer.transformation(tr2 * sc * tr1); +} + ////////////////////////////////////// // painter_stroke_test methods painter_stroke_test:: @@ -309,10 +387,10 @@ painter_stroke_test(void): m_radial_gradient_change_rate(0.1f, "change_rate_brush_radial_gradient", "rate of change in pixels/sec when changing the radial gradient radius", *this), - m_path_file("", "path_file", - "if non-empty read the geometry of the path from the specified file, " - "otherwise use a default path", - *this), + m_path_file_list("add_path_file", + "add a path read from file to path list; if path list is empty then " + "a default path will be used to render ", + *this), m_dash_pattern_files(*this), m_print_path(false, "print_path", "If true, print the geometry data of the path drawn to stdout", @@ -333,10 +411,8 @@ painter_stroke_test(void): "sub-image height of sub-image rectange (negative value means no-subimage)", *this), m_font_file(default_font(), "font", "File from which to take font", *this), - m_path_from_glyph(false, "path_from_glyph", - "If true, draw a path from a glyph of the font", *this), - m_character_code('W', "path_character_code", - "If path_from_glyph is true, selects which glyph via character code to use", *this), + m_character_code_list("add_path_character_code", + "add a path of a glyph selected via character code", *this), m_stroke_red(1.0f, "stroke_red", "red component of stroking pen color", *this), m_stroke_green(1.0f, "stroke_green", "green component of stroking pen color", *this), m_stroke_blue(1.0f, "stroke_blue", "blue component of stroking pen olor", *this), @@ -345,12 +421,11 @@ painter_stroke_test(void): m_fill_green(1.0f, "fill_green", "green component of fill pen color", *this), m_fill_blue(1.0f, "fill_blue", "blue component of fill pen color", *this), m_fill_alpha(1.0f, "fill_alpha", "alpha component of fill pen color", *this), + m_selected_path(0), m_join_style(PainterEnums::miter_clip_joins), m_cap_style(PainterEnums::square_caps), m_close_contour(true), - m_fill_rule(PainterEnums::odd_even_fill_rule), m_dash(0), - m_end_fill_rule(PainterEnums::fill_rule_data_count), m_have_miter_limit(true), m_miter_limit(5.0f), m_stroke_width(10.0f), @@ -367,17 +442,15 @@ painter_stroke_test(void): m_with_aa(true), m_wire_frame(false), m_stroke_width_in_pixels(false), - m_stroke_width_pixels_scaled_by_zoom(false), m_force_square_viewport(false), m_fill_by_clipping(false), - m_shear(1.0f, 1.0f), - m_shear2(1.0f, 1.0f), m_draw_grid(false), m_angle(0.0f), m_grid_path_dirty(true), m_clip_window_path_dirty(true) { std::cout << "Controls:\n" + << "\tk: select next path\n" << "\ta: toggle anti-aliased stroking\n" << "\tj: cycle through join styles for stroking\n" << "\tc: cycle through cap style for stroking\n" @@ -472,11 +545,11 @@ update_cts_params(void) speed_shear = -speed_shear; } - vec2 *pshear(&m_shear); + vec2 *pshear(&shear()); c_string shear_txt = ""; if (keyboard_state[SDL_SCANCODE_RETURN]) { - pshear = &m_shear2; + pshear = &shear2(); shear_txt = "2"; } @@ -505,7 +578,7 @@ update_cts_params(void) speed_stroke = speed * m_change_stroke_width_rate.m_value; if (!m_stroke_width_in_pixels) { - speed_stroke /= m_zoomer.transformation().scale(); + speed_stroke /= zoomer().transformation().scale(); } if (keyboard_state[SDL_SCANCODE_RIGHTBRACKET]) @@ -531,7 +604,7 @@ update_cts_params(void) vec2 *changer; float delta, delta_y; - delta = m_window_change_rate.m_value * speed / m_zoomer.transformation().scale(); + delta = m_window_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL]) { changer = &m_repeat_wh; @@ -578,7 +651,7 @@ update_cts_params(void) { float delta; - delta = m_radial_gradient_change_rate.m_value * speed / m_zoomer.transformation().scale(); + delta = m_radial_gradient_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_1]) { m_gradient_r0 -= delta; @@ -633,7 +706,7 @@ update_cts_params(void) vec2 *changer; float delta, delta_y; - delta = m_window_change_rate.m_value * speed / m_zoomer.transformation().scale(); + delta = m_window_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL]) { changer = &m_clipping_wh; @@ -685,12 +758,12 @@ brush_item_coordinate(ivec2 scr) if (m_matrix_brush) { - p *= m_zoomer.transformation().scale(); + p *= zoomer().transformation().scale(); } if (m_translate_brush) { - p += m_zoomer.transformation().translation(); + p += zoomer().transformation().translation(); } return p; } @@ -701,13 +774,13 @@ item_coordinates(ivec2 scr) { vec2 p(scr); - /* unapply m_zoomer + /* unapply zoomer() */ - p = m_zoomer.transformation().apply_inverse_to_point(p); + p = zoomer().transformation().apply_inverse_to_point(p); - /* unapply m_shear + /* unapply shear() */ - p /= m_shear; + p /= shear(); /* unapply rotation by m_angle */ @@ -724,9 +797,9 @@ item_coordinates(ivec2 scr) p = tr * p; - /* unapply m_shear2 + /* unapply shear2() */ - p /= m_shear2; + p /= shear2(); return p; } @@ -735,7 +808,7 @@ void painter_stroke_test:: handle_event(const SDL_Event &ev) { - m_zoomer.handle_event(ev); + zoomer().handle_event(ev); switch(ev.type) { case SDL_QUIT: @@ -774,20 +847,8 @@ handle_event(const SDL_Event &ev) break; case SDLK_k: - if (m_stroke_width_in_pixels) - { - m_stroke_width_pixels_scaled_by_zoom = !m_stroke_width_pixels_scaled_by_zoom; - std::cout << "Stroke width pixels scale by zoom factor: "; - if (m_stroke_width_pixels_scaled_by_zoom) - { - std::cout << "ON"; - } - else - { - std::cout << "OFF"; - } - std::cout << "\n"; - } + cycle_value(m_selected_path, ev.key.keysym.mod & (KMOD_SHIFT|KMOD_CTRL|KMOD_ALT), m_paths.size()); + std::cout << "Path " << m_paths[m_selected_path].m_label << " selected\n"; break; case SDLK_a: @@ -812,7 +873,7 @@ handle_event(const SDL_Event &ev) break; case SDLK_q: - m_shear = m_shear2 = vec2(1.0f, 1.0f); + shear() = shear2() = vec2(1.0f, 1.0f); break; case SDLK_p: @@ -969,12 +1030,14 @@ handle_event(const SDL_Event &ev) case SDLK_r: if (m_draw_fill) { - cycle_value(m_fill_rule, ev.key.keysym.mod & (KMOD_SHIFT|KMOD_CTRL|KMOD_ALT), m_end_fill_rule + 1); - if (m_fill_rule < PainterEnums::fill_rule_data_count) + cycle_value(current_fill_rule(), + ev.key.keysym.mod & (KMOD_SHIFT|KMOD_CTRL|KMOD_ALT), + current_end_fill_rule() + 1); + if (current_fill_rule() < PainterEnums::fill_rule_data_count) { - std::cout << "Fill rule set to: " << m_fill_labels[m_fill_rule] << "\n"; + std::cout << "Fill rule set to: " << m_fill_labels[current_fill_rule()] << "\n"; } - else if (m_fill_rule == m_end_fill_rule) + else if (current_fill_rule() == current_end_fill_rule()) { std::cout << "Fill rule set to custom fill rule: all winding numbers filled\n"; } @@ -982,8 +1045,8 @@ handle_event(const SDL_Event &ev) { c_array wnd; int value; - wnd = m_path.tessellation()->filled()->subset(0).winding_numbers(); - value = wnd[m_fill_rule - PainterEnums::fill_rule_data_count]; + wnd = path().tessellation()->filled()->subset(0).winding_numbers(); + value = wnd[current_fill_rule() - PainterEnums::fill_rule_data_count]; std::cout << "Fill rule set to custom fill rule: winding_number == " << value << "\n"; } @@ -1058,122 +1121,134 @@ handle_event(const SDL_Event &ev) void painter_stroke_test:: -construct_path(void) +construct_paths(int w, int h) { - if (m_path_from_glyph.m_value) + for(const std::string &file : m_path_file_list) + { + std::ifstream path_file(file.c_str()); + if (path_file) + { + std::stringstream buffer; + Path P; + + buffer << path_file.rdbuf(); + read_path(P, buffer.str()); + if (P.number_contours() > 0) + { + m_paths.push_back(PerPath(P, file, w, h)); + } + } + } + + for (uint32_t character_code : m_character_code_list) { uint32_t glyph_code; GlyphRender renderer(distance_field_glyph); Glyph g; - glyph_code = m_font->glyph_code(m_character_code.m_value); + glyph_code = m_font->glyph_code(character_code); g = m_glyph_cache->fetch_glyph(renderer, m_font, glyph_code); - if (g.valid()) + if (g.valid() && g.path().number_contours() > 0) { - m_path = g.path(); - return; + std::ostringstream str; + str << "character code:" << character_code; + m_paths.push_back(PerPath(g.path(), str.str(), w, h)); } } - if (!m_path_file.m_value.empty()) + if (m_paths.empty()) { - std::ifstream path_file(m_path_file.m_value.c_str()); - if (path_file) - { - std::stringstream buffer; - buffer << path_file.rdbuf(); - read_path(m_path, buffer.str()); - return; - } + Path path; + + path << vec2(50.0f, 35.0f) + << Path::control_point(60.0f, 50.0f) + << vec2(70.0f, 35.0f) + << Path::arc_degrees(180.0, vec2(70.0f, -100.0f)) + << Path::control_point(60.0f, -150.0f) + << Path::control_point(30.0f, -50.0f) + << vec2(0.0f, -100.0f) + << Path::contour_end_arc_degrees(90.0f) + << vec2(200.0f, 200.0f) + << vec2(400.0f, 200.0f) + << vec2(400.0f, 400.0f) + << vec2(200.0f, 400.0f) + << Path::contour_end() + << vec2(-50.0f, 100.0f) + << vec2(0.0f, 200.0f) + << vec2(100.0f, 300.0f) + << vec2(150.0f, 325.0f) + << vec2(150.0f, 100.0f) + << Path::contour_end() + << vec2(300.0f, 300.0f) + << Path::contour_end(); + m_paths.push_back(PerPath(path, "Default Path", w, h)); } - - m_path << vec2(50.0f, 35.0f) - << Path::control_point(60.0f, 50.0f) - << vec2(70.0f, 35.0f) - << Path::arc_degrees(180.0, vec2(70.0f, -100.0f)) - << Path::control_point(60.0f, -150.0f) - << Path::control_point(30.0f, -50.0f) - << vec2(0.0f, -100.0f) - << Path::contour_end_arc_degrees(90.0f) - << vec2(200.0f, 200.0f) - << vec2(400.0f, 200.0f) - << vec2(400.0f, 400.0f) - << vec2(200.0f, 400.0f) - << Path::contour_end() - << vec2(-50.0f, 100.0f) - << vec2(0.0f, 200.0f) - << vec2(100.0f, 300.0f) - << vec2(150.0f, 325.0f) - << vec2(150.0f, 100.0f) - << Path::contour_end() - << vec2(300.0f, 300.0f) - << Path::contour_end(); } void painter_stroke_test:: -create_stroked_path_attributes(void) +per_path_processing(void) { - reference_counted_ptr tessellated; - reference_counted_ptr stroked; - const PainterAttributeData *data; - c_array miter_points; - - tessellated = m_path.tessellation(-1.0f); - stroked = tessellated->stroked(); - data = &stroked->miter_clip_joins(); - m_miter_limit = 0.0f; - for(unsigned int J = 0, endJ = stroked->number_joins(true); J < endJ; ++J) + for(const PerPath &P : m_paths) { - unsigned int chunk; + reference_counted_ptr tess; + reference_counted_ptr stroked; + const PainterAttributeData *data; + c_array miter_points; - chunk = stroked->join_chunk(J); - miter_points = data->attribute_data_chunk(chunk); - for(unsigned p = 0, endp = miter_points.size(); p < endp; ++p) + tess = P.m_path.tessellation(-1.0f); + stroked = tess->stroked(); + data = &stroked->miter_clip_joins(); + + for(unsigned int J = 0, endJ = stroked->number_joins(true); J < endJ; ++J) { - float v; - StrokedPath::point pt; + unsigned int chunk; - StrokedPath::point::unpack_point(&pt, miter_points[p]); - v = pt.miter_distance(); - if (std::isfinite(v)) + chunk = stroked->join_chunk(J); + miter_points = data->attribute_data_chunk(chunk); + for(unsigned p = 0, endp = miter_points.size(); p < endp; ++p) { - m_miter_limit = fastuidraw::t_max(m_miter_limit, fastuidraw::t_abs(v)); + float v; + StrokedPath::point pt; + + StrokedPath::point::unpack_point(&pt, miter_points[p]); + v = pt.miter_distance(); + if (std::isfinite(v)) + { + m_miter_limit = fastuidraw::t_max(m_miter_limit, fastuidraw::t_abs(v)); + } } } - } - m_miter_limit = fastuidraw::t_min(100.0f, m_miter_limit); //100 is an insane miter limit. - - if (m_print_path.m_value) - { - reference_counted_ptr tess; - tess = m_path.tessellation(); - std::cout << "Path tessellated:\n"; - for(unsigned int c = 0; c < tess->number_contours(); ++c) + if (m_print_path.m_value) { - std::cout << "\tContour #" << c << "\n"; - for(unsigned int e = 0; e < tess->number_edges(c); ++e) + std::cout << "Path \"" << P.m_label << "\" tessellated:\n"; + for(unsigned int c = 0; c < tess->number_contours(); ++c) { - fastuidraw::c_array pts; - - std::cout << "\t\tEdge #" << e << " has " - << tess->edge_point_data(c, e).size() << " pts\n"; - pts = tess->edge_point_data(c, e); - for(unsigned int i = 0; i < pts.size(); ++i) + std::cout << "\tContour #" << c << "\n"; + for(unsigned int e = 0; e < tess->number_edges(c); ++e) { - std::cout << "\t\t\tPoint #" << i << ":\n" - << "\t\t\t\tp = " << pts[i].m_p << "\n" - << "\t\t\t\tedge_d = " << pts[i].m_distance_from_edge_start << "\n" - << "\t\t\t\tcontour_d = " << pts[i].m_distance_from_contour_start << "\n" - << "\t\t\t\tedge_l = " << pts[i].m_edge_length << "\n" - << "\t\t\t\tcontour_l = " << pts[i].m_open_contour_length << "\n" - << "\t\t\t\tcontour_cl = " << pts[i].m_closed_contour_length << "\n"; + fastuidraw::c_array pts; + + std::cout << "\t\tEdge #" << e << " has " + << tess->edge_point_data(c, e).size() << " pts\n"; + pts = tess->edge_point_data(c, e); + for(unsigned int i = 0; i < pts.size(); ++i) + { + std::cout << "\t\t\tPoint #" << i << ":\n" + << "\t\t\t\tp = " << pts[i].m_p << "\n" + << "\t\t\t\tedge_d = " << pts[i].m_distance_from_edge_start << "\n" + << "\t\t\t\tcontour_d = " << pts[i].m_distance_from_contour_start << "\n" + << "\t\t\t\tedge_l = " << pts[i].m_edge_length << "\n" + << "\t\t\t\tcontour_l = " << pts[i].m_open_contour_length << "\n" + << "\t\t\t\tcontour_cl = " << pts[i].m_closed_contour_length << "\n"; + } } } } } + m_miter_limit = fastuidraw::t_min(100.0f, m_miter_limit); //100 is an insane miter limit. } void @@ -1319,13 +1394,13 @@ draw_frame(void) false); } - /* apply m_zoomer + /* apply zoomer() */ - m_painter->concat(m_zoomer.transformation().matrix3()); + m_painter->concat(zoomer().transformation().matrix3()); /* apply shear */ - m_painter->shear(m_shear.x(), m_shear.y()); + m_painter->shear(shear().x(), shear().y()); /* apply rotation */ @@ -1333,7 +1408,7 @@ draw_frame(void) /* apply shear2 */ - m_painter->shear(m_shear2.x(), m_shear2.y()); + m_painter->shear(shear2().x(), shear2().y()); if (m_clipping_window) { @@ -1374,7 +1449,7 @@ draw_frame(void) m_fill_blue.m_value, m_fill_alpha.m_value); if (m_translate_brush) { - fill_brush.transformation_translate(m_zoomer.transformation().translation()); + fill_brush.transformation_translate(zoomer().transformation().translation()); } else { @@ -1384,7 +1459,7 @@ draw_frame(void) if (m_matrix_brush) { float2x2 m; - m(0, 0) = m(1, 1) = m_zoomer.transformation().scale(); + m(0, 0) = m(1, 1) = zoomer().transformation().scale(); fill_brush.transformation_matrix(m); } else @@ -1448,17 +1523,17 @@ draw_frame(void) WindingValueFillRule value_fill_rule; CustomFillRuleBase *fill_rule(&fill_rule_function); - if (m_fill_rule < PainterEnums::fill_rule_data_count) + if (current_fill_rule() < PainterEnums::fill_rule_data_count) { - fill_rule_function = CustomFillRuleFunction(static_cast(m_fill_rule)); + fill_rule_function = CustomFillRuleFunction(static_cast(current_fill_rule())); } - else if (m_fill_rule != m_end_fill_rule) + else if (current_fill_rule() != current_end_fill_rule()) { int value; c_array wnd; - wnd = m_path.tessellation()->filled()->subset(0).winding_numbers(); - value = wnd[m_fill_rule - PainterEnums::fill_rule_data_count]; + wnd = path().tessellation()->filled()->subset(0).winding_numbers(); + value = wnd[current_fill_rule() - PainterEnums::fill_rule_data_count]; value_fill_rule = WindingValueFillRule(value); fill_rule = &value_fill_rule; } @@ -1466,14 +1541,15 @@ draw_frame(void) if (m_fill_by_clipping) { m_painter->save(); - m_painter->clipInPath(m_path, *fill_rule); + m_painter->clipInPath(path(), *fill_rule); m_painter->transformation(float3x3()); m_painter->draw_rect(PainterData(&fill_brush), vec2(-1.0f, -1.0f), vec2(2.0f, 2.0f), false); m_painter->restore(); } else { - m_painter->fill_path(PainterData(&fill_brush), m_path, *fill_rule, m_with_aa && !m_aa_fill_by_stroking); + m_painter->fill_path(PainterData(&fill_brush), path(), + *fill_rule, m_with_aa && !m_aa_fill_by_stroking); } if (m_aa_fill_by_stroking && m_with_aa) @@ -1481,7 +1557,8 @@ draw_frame(void) PainterStrokeParams st; st.miter_limit(-1.0f); st.width(2.0f); - m_painter->stroke_path_pixel_width(PainterData(&fill_brush, &st), m_path, true, + m_painter->stroke_path_pixel_width(PainterData(&fill_brush, &st), + path(), true, PainterEnums::flat_caps, PainterEnums::bevel_joins, true); @@ -1491,8 +1568,8 @@ draw_frame(void) if (!m_stroke_pen) { - PainterBrush br; - br.pen(m_stroke_red.m_value, m_stroke_green.m_value, m_stroke_blue.m_value, m_stroke_alpha.m_value); + PainterBrush br; + br.pen(m_stroke_red.m_value, m_stroke_green.m_value, m_stroke_blue.m_value, m_stroke_alpha.m_value); m_stroke_pen = m_painter->packed_value_pool().create_packed_value(br); } @@ -1513,13 +1590,14 @@ draw_frame(void) st.width(m_stroke_width); unsigned int D(dash_pattern()); - c_array dash_ptr(&m_dash_patterns[D][0], m_dash_patterns[D].size()); + c_array dash_ptr(&m_dash_patterns[D][0], + m_dash_patterns[D].size()); st.dash_pattern(dash_ptr); if (m_stroke_width_in_pixels) { m_painter->stroke_dashed_path_pixel_width(PainterData(m_stroke_pen, &st), - m_path, m_close_contour, + path(), m_close_contour, static_cast(m_cap_style), static_cast(m_join_style), m_with_aa); @@ -1527,7 +1605,7 @@ draw_frame(void) else { m_painter->stroke_dashed_path(PainterData(m_stroke_pen, &st), - m_path, m_close_contour, + path(), m_close_contour, static_cast(m_cap_style), static_cast(m_join_style), m_with_aa); @@ -1548,12 +1626,8 @@ draw_frame(void) if (m_stroke_width_in_pixels) { - if (m_stroke_width_pixels_scaled_by_zoom) - { - st.width(m_stroke_width * m_zoomer.transformation().scale()); - } m_painter->stroke_path_pixel_width(PainterData(m_stroke_pen, &st), - m_path, m_close_contour, + path(), m_close_contour, static_cast(m_cap_style), static_cast(m_join_style), m_with_aa); @@ -1561,7 +1635,7 @@ draw_frame(void) else { m_painter->stroke_path(PainterData(m_stroke_pen, &st), - m_path, m_close_contour, + path(), m_close_contour, static_cast(m_cap_style), static_cast(m_join_style), m_with_aa); @@ -1576,7 +1650,7 @@ draw_frame(void) vec2 p0, p1; float inv_scale; - inv_scale = 1.0f / m_zoomer.transformation().scale(); + inv_scale = 1.0f / zoomer().transformation().scale(); r0 = 15.0f * inv_scale; r1 = 30.0f * inv_scale; @@ -1585,8 +1659,8 @@ draw_frame(void) if (m_translate_brush) { - p0 -= m_zoomer.transformation().translation(); - p1 -= m_zoomer.transformation().translation(); + p0 -= zoomer().transformation().translation(); + p1 -= zoomer().transformation().translation(); } if (m_matrix_brush) @@ -1628,6 +1702,7 @@ draw_frame(void) } ostr << "\nms = " << us / 1000.0f + << "\nDrawing Path: " << m_paths[m_selected_path].m_label << "\nAttribs: " << m_painter->query_stat(PainterPacker::num_attributes) << "\nIndices: " @@ -1688,12 +1763,10 @@ derived_init(int w, int h) << "-----------------------------------------------------\n"; } - construct_path(); - create_stroked_path_attributes(); + construct_paths(w, h); + per_path_processing(); construct_color_stops(); construct_dash_patterns(); - m_end_fill_rule = - m_path.tessellation()->filled()->subset(0).winding_numbers().size() + PainterEnums::fill_rule_data_count; /* set shader anti-alias to false if doing msaa rendering */ if (m_surface->properties().msaa() > 1) @@ -1701,24 +1774,6 @@ derived_init(int w, int h) m_with_aa = false; } - /* set transformation to center and contain path. - */ - vec2 p0, p1, delta, dsp(w, h), ratio, mid; - float mm; - p0 = m_path.tessellation()->bounding_box_min(); - p1 = m_path.tessellation()->bounding_box_max(); - - delta = p1 - p0 + vec2(m_stroke_width, m_stroke_width); - ratio = delta / dsp; - mm = t_max(0.00001f, t_max(ratio.x(), ratio.y()) ); - mid = 0.5 * (p1 + p0); - - ScaleTranslate sc, tr1, tr2; - tr1.translation(-mid); - sc.scale( 1.0f / mm); - tr2.translation(dsp * 0.5f); - m_zoomer.transformation(tr2 * sc * tr1); - if (!m_image_file.m_value.empty()) { std::vector image_data; @@ -1751,12 +1806,12 @@ derived_init(int w, int h) m_gradient_p1 = item_coordinates(ivec2(w, h)); m_gradient_r0 = 0.0f; - m_gradient_r1 = 200.0f / m_zoomer.transformation().scale(); + m_gradient_r1 = 200.0f / zoomer().transformation().scale(); m_repeat_xy = vec2(0.0f, 0.0f); - m_repeat_wh = m_path.tessellation()->bounding_box_max() - m_path.tessellation()->bounding_box_min(); + m_repeat_wh = path().tessellation()->bounding_box_max() - path().tessellation()->bounding_box_min(); - m_clipping_xy = m_path.tessellation()->bounding_box_min(); + m_clipping_xy = path().tessellation()->bounding_box_min(); m_clipping_wh = m_repeat_wh; m_curve_flatness = m_painter->curveFlatness(); From dd02e6e23d6ed86465ec3bbddd5fd368cea76a31 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 20:55:54 +0300 Subject: [PATCH 02/52] fastuidraw/path: new arc ctor + minor cleanups Change-Id: I6f2a41392b6a776ee30e72bff9f9a89fe6eaa572 --- inc/fastuidraw/path.hpp | 10 +++++++ src/fastuidraw/path.cpp | 63 +++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index df9adee33..78cbe5668 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -329,6 +329,16 @@ class PathContour: */ arc(const reference_counted_ptr &start, float angle, const vec2 &end); + /*! + * Ctor. + * \param start start of curve + * \param center center of curve + * \param end end of curve; if the point is collinear with start and center + * then it is undefined if the arc flips one way or the other + * along the circle. + */ + arc(const reference_counted_ptr &start, + const vec2 ¢er, const vec2 &end); ~arc(); diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 0629b0e20..60a18b5a3 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -24,6 +24,7 @@ #include #include "private/util_private.hpp" #include "private/path_util_private.hpp" +#include "private/bounding_box.hpp" namespace { @@ -94,6 +95,7 @@ namespace tessellation_satsified(unsigned int recurse_level, fastuidraw::c_array threshholds) { + FASTUIDRAWunused(recurse_level); return (threshholds[m_thresh.m_threshhold_type] < m_thresh.m_threshhold); } @@ -189,6 +191,37 @@ namespace float m_start_angle; fastuidraw::vec2 m_center; fastuidraw::vec2 m_min_bb, m_max_bb; + + void + compute_bb(void) + { + using namespace fastuidraw; + + vec2 p0, p1, z; + float d; + + p0 = vec2(t_cos(m_start_angle), + t_sin(m_start_angle)); + + p1 = vec2(t_cos(m_start_angle + m_angle_speed), + t_sin(m_start_angle + m_angle_speed)); + + d = 1.0f - t_cos(m_angle_speed * 0.5f); + + /* + * bb represents the bounding box of an arc + * [m_start_angle, m_start_angle + m_angle_speed) + * with radius one centered at the origin + */ + BoundingBox bb; + bb.union_point(p0); + bb.union_point(p1); + bb.union_point(p0 + d * z); + bb.union_point(p1 + d * z); + + m_min_bb = m_center + m_radius * bb.min_point(); + m_max_bb = m_center + m_radius * bb.max_point(); + } }; class PathContourPrivate @@ -765,18 +798,30 @@ arc(const reference_counted_ptr &start, float angle, co d->m_start_angle = std::atan2(start_center.y(), start_center.x()); d->m_angle_speed = angle_coeff_dir * angle; - vec2 p0, p1; - p0 = vec2(std::cos(d->m_start_angle), std::sin(d->m_start_angle)); - p1 = vec2(std::cos(d->m_start_angle + d->m_angle_speed), std::sin(d->m_start_angle + d->m_angle_speed)); + d->compute_bb(); +} - d->m_min_bb.x() = fastuidraw::t_min(p0.x(), p1.x()); - d->m_min_bb.y() = fastuidraw::t_min(p0.y(), p1.y()); +fastuidraw::PathContour::arc:: +arc(const reference_counted_ptr &start, + const vec2 ¢er, const vec2 &end): + fastuidraw::PathContour::interpolator_base(start, end) +{ + ArcPrivate *d; + d = FASTUIDRAWnew ArcPrivate(); + m_d = d; + + vec2 start_center(start_pt() - center); + vec2 end_center(end - center); + float end_angle; + + end_angle = std::atan2(end_center.y(), end_center.x()); - d->m_max_bb.x() = fastuidraw::t_max(p0.x(), p1.x()); - d->m_max_bb.y() = fastuidraw::t_max(p0.y(), p1.y()); + d->m_center = center; + d->m_radius = start_center.magnitude(); + d->m_start_angle = std::atan2(start_center.y(), start_center.x()); + d->m_angle_speed = end_angle - d->m_start_angle; - d->m_min_bb = d->m_center + d->m_radius * d->m_min_bb; - d->m_max_bb = d->m_center + d->m_radius * d->m_max_bb; + d->compute_bb(); } fastuidraw::PathContour::arc:: From da86b03c8dd7a859a2b7ce1200c45c7b36aa3c1d Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 21:08:34 +0300 Subject: [PATCH 03/52] fastuidraw/painter: move StrokedPath::point to global class StrokedPoint Change-Id: I4e41fbc4a9d112ad5a68d15d7b2812549494ff88 --- inc/fastuidraw/painter/stroked_path.hpp | 532 +-------------------- inc/fastuidraw/painter/stroked_point.hpp | 565 +++++++++++++++++++++++ src/fastuidraw/painter/Rules.mk | 2 +- src/fastuidraw/painter/stroked_path.cpp | 156 ------- src/fastuidraw/painter/stroked_point.cpp | 157 +++++++ 5 files changed, 725 insertions(+), 687 deletions(-) create mode 100644 inc/fastuidraw/painter/stroked_point.hpp create mode 100644 src/fastuidraw/painter/stroked_point.cpp diff --git a/inc/fastuidraw/painter/stroked_path.hpp b/inc/fastuidraw/painter/stroked_path.hpp index 0b1bd80ac..3911e7f52 100644 --- a/inc/fastuidraw/painter/stroked_path.hpp +++ b/inc/fastuidraw/painter/stroked_path.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace fastuidraw { @@ -59,536 +60,7 @@ class StrokedPath: public reference_counted::non_concurrent { public: - /*! - * \brief - * A point holds the data for a point of stroking. - * The data is so that changing the stroking width - * or miter limit does not change the stroking data. - */ - class point - { - public: - - /*! - * \brief - * Enumeration for specifing how to compute - * \ref offset_vector()). - */ - enum offset_type_t - { - /*! - * The point is for an edge of the path, - * point signifies the start of a sub-edge - * (quad) of drawing an edge. - */ - offset_start_sub_edge, - - /*! - * The point is for an edge of the path, - * point signifies the end of a sub-edge - * (quad) of drawing an edge. - */ - offset_end_sub_edge, - - /*! - * The point is at a position that has the - * same value as point on an edge but the - * point itself is part of a cap or join. - */ - offset_shared_with_edge, - - /*! - * The point is for a boundary point of a rounded join of the path - */ - offset_rounded_join, - - /*! - * Point type for miter-clip join point whose position - * depends on the miter-limit. - */ - offset_miter_clip_join, - - /*! - * Point type for miter-clip join point whose position - * depends on the miter-limit where the lambda of the - * computation is negatted. - */ - offset_miter_clip_join_lambda_negated, - - /*! - * Point type for miter-bevel join point whose position - * depends on the miter-limit. - */ - offset_miter_bevel_join, - - /*! - * Point type for miter join whose position depends on - * the miter-limit. - */ - offset_miter_join, - - /*! - * The point is for a boundary point of a rounded cap of the path - */ - offset_rounded_cap, - - /*! - * The point is for a boundary point of a square cap of the path - */ - offset_square_cap, - - /*! - * The point is from \ref adjustable_caps() point set. - * It is for a point for a cap at the start of a contour. - * These points are for dashed stroking with caps; they - * contain data to allow one from a vertex shader to extend - * or shrink the cap area correctly to implement dashed - * stroking. - */ - offset_adjustable_cap_contour_start, - - /*! - * The point is from \ref adjustable_caps() point set. - * It is for a point for a cap at the end of a contour. - * These points are for dashed stroking with caps; they - * contain data to allow one from a vertex shader to extend - * or shrink the cap area correctly to implement dashed - * stroking. - */ - offset_adjustable_cap_contour_end, - - /*! - * Number different point types with respect to rendering - */ - number_offset_types - }; - - /*! - * \brief - * Enumeration encoding of bits of point::m_packed_data - * common to all offset types. - */ - enum packed_data_bit_layout_common_t - { - /*! - * Bit0 for holding the offset_type() value - * of the point. - */ - offset_type_bit0 = 0, - - /*! - * number of bits needed to hold the - * offset_type() value of the point. - */ - offset_type_num_bits = 4, - - /*! - * Bit for holding boundary() value - * of the point - */ - boundary_bit = offset_type_bit0 + offset_type_num_bits, - - /*! - * Bit0 for holding the depth() value - * of the point - */ - depth_bit0, - - /*! - * number of bits needed to hold the - * depth() value of the point. - */ - depth_num_bits = 20, - - /*! - * Bit to indicate point is from a join. For these - * points, during dashed stroking, Painter does the - * check if a join should be drawn, as such when the - * bit is up encountered in a shader, the computation - * to check that it is drawn from dashing can be - * skipped and assume that fragments from such points - * are covered by the dash pattern. - */ - join_bit = depth_bit0 + depth_num_bits, - - /*! - * Number of bits used on common packed data - */ - number_common_bits, - }; - - /*! - * \brief - * Enumeration encoding of bits of point::m_packed_data - * for those with offset type \ref offset_rounded_join - */ - enum packed_data_bit_layout_rounded_join_t - { - /*! - * Bit for holding the the sign of - * the y-coordinate of the normal 0 - * for the offset_type() \ref - * offset_rounded_join. - */ - normal0_y_sign_bit = number_common_bits, - - /*! - * Bit for holding the the sign of - * the y-coordinate of the normal 1 - * for the offset_type() \ref - * offset_rounded_join. - */ - normal1_y_sign_bit, - - /*! - * Bit for holding the the sign of - * sin() value for the offset_type() - * \ref offset_rounded_join. - */ - sin_sign_bit, - }; - - /*! - * \brief - * Enumeration encoding of bits of point::m_packed_data for - * those with offset type \ref offset_adjustable_cap_contour_end - * or \ref offset_adjustable_cap_contour_start. - */ - enum packed_data_bit_adjustable_cap_t - { - /*! - * The bit is up if the point is for end of point - * of a cap (i.e. the side to be extended to make - * sure the entire cap near the end of edge is drawn). - */ - adjustable_cap_ending_bit = number_common_bits, - }; - - /*! - * \brief - * Enumeration encoding of bits of point::m_packed_data - * for those with offset type \ref offset_start_sub_edge - * or \ref offset_end_sub_edge. - */ - enum packed_data_bit_sub_edge_t - { - /*! - * The bit is up if the point is for the - * geometry of a bevel between two sub-edges. - */ - bevel_edge_bit = number_common_bits, - }; - - /*! - * \brief - * Enumeration holding bit masks generated from - * values in \ref packed_data_bit_layout_common_t, - * \ref packed_data_bit_layout_rounded_join_t, - * \ref packed_data_bit_adjustable_cap_t and \ref - * packed_data_bit_sub_edge_t. - */ - enum packed_data_bit_masks_t - { - /*! - * Mask generated for \ref offset_type_bit0 and - * \ref offset_type_num_bits - */ - offset_type_mask = FASTUIDRAW_MASK(offset_type_bit0, offset_type_num_bits), - - /*! - * Mask generated for \ref normal0_y_sign_bit - */ - normal0_y_sign_mask = FASTUIDRAW_MASK(normal0_y_sign_bit, 1), - - /*! - * Mask generated for \ref normal1_y_sign_bit - */ - normal1_y_sign_mask = FASTUIDRAW_MASK(normal1_y_sign_bit, 1), - - /*! - * Mask generated for \ref sin_sign_bit sin_sign_bit - */ - sin_sign_mask = FASTUIDRAW_MASK(sin_sign_bit, 1), - - /*! - * Mask generated for \ref boundary_bit - */ - boundary_mask = FASTUIDRAW_MASK(boundary_bit, 1), - - /*! - * Mask generated for \ref join_bit - */ - join_mask = FASTUIDRAW_MASK(join_bit, 1), - - /*! - * Mask generated for \ref adjustable_cap_ending_bit - */ - adjustable_cap_ending_mask = FASTUIDRAW_MASK(adjustable_cap_ending_bit, 1), - - /*! - * Mask generated for \ref bevel_edge_bit - */ - bevel_edge_mask = FASTUIDRAW_MASK(bevel_edge_bit, 1), - - /*! - * Mask generated for \ref depth_bit0 and \ref depth_num_bits - */ - depth_mask = FASTUIDRAW_MASK(depth_bit0, depth_num_bits), - }; - - /*! - * The base position of a point, taken directly from - * the TessellatedPath from which the - * StrokedPath is constructed. - */ - vec2 m_position; - - /*! - * Gives the offset vector used to help compute - * the point offset vector. - */ - vec2 m_pre_offset; - - /*! - * Provides an auxiliary offset data - */ - vec2 m_auxiliary_offset; - - /*! - * Gives the distance of the point from the start - * of the -edge- on which the point resides. - */ - float m_distance_from_edge_start; - - /*! - * Gives the distance of the point from the start - * of the -contour- on which the point resides. - */ - float m_distance_from_contour_start; - - /*! - * Gives the length of the edge on which the - * point lies. This value is the same for all - * points along a fixed edge. - */ - float m_edge_length; - - /*! - * Gives the length of the contour open on which - * the point lies. This value is the same for all - * points along a fixed contour. - */ - float m_open_contour_length; - - /*! - * Gives the length of the contour closed on which - * the point lies. This value is the same for all - * points along a fixed contour. - */ - float m_closed_contour_length; - - /*! - * Bit field with data packed as according to - * \ref packed_data_bit_layout_common_t, \ref - * packed_data_bit_layout_rounded_join_t, \ref - * packed_data_bit_adjustable_cap_t and \ref - * packed_data_bit_sub_edge_t. See also, - * \ref packed_data_bit_masks_t for bit masks - * generated. - */ - uint32_t m_packed_data; - - /*! - * Provides the point type from a value of \ref m_packed_data. - * The return value is one of the enumerations of - * \ref offset_type_t. - * \param packed_data_value value suitable for \ref m_packed_data - */ - static - enum offset_type_t - offset_type(uint32_t packed_data_value) - { - uint32_t v; - v = unpack_bits(offset_type_bit0, offset_type_num_bits, packed_data_value); - return static_cast(v); - } - - /*! - * Provides the point type for the point. The return value - * is one of the enumerations of \ref offset_type_t. - */ - enum offset_type_t - offset_type(void) const - { - return offset_type(m_packed_data); - } - - /*! - * When stroking the data, the depth test to only - * pass when the depth value is -strictly- larger - * so that a fixed pixel is not stroked twice by - * a single path. The value returned by depth() is - * a relative z-value for a vertex. The points - * drawn first have the largest z-values. - */ - uint32_t - depth(void) const - { - return unpack_bits(depth_bit0, depth_num_bits, m_packed_data); - } - - /*! - * Has value 0 or 1. If the value is 0, then - * the point is on the path. If the value has - * absolute value 1, then indicates a point that - * is on the boundary of the stroked path. The triangles - * produced from stroking are so that when - * on_boundary() is interpolated across the triangle - * the center of stroking the value is 0 and the - * value has value 1 on the boundary. - */ - int - on_boundary(void) const - { - return unpack_bits(boundary_bit, 1u, m_packed_data); - } - - /*! - * Computes the offset vector for a point. The final position - * of a point when stroking with a width of W is given by - * \code - * m_position + 0.5f * W * offset_vector(). - * \endcode - * The computation for offset_vector() is as follows. - * - For those with offset_type() being \ref offset_start_sub_edge, - * \ref offset_end_sub_edge and \ref offset_shared_with_edge, - * the offset is given by - * \code - * m_pre_offset - * \endcode - * In addition, for these offset types, \ref m_auxiliary_offset - * holds the the delta vector to the point on edge with - * which the point makes a quad. - * - For those with offset_type() being \ref offset_rounded_join, - * the value is given by the following code - * \code - * vec2 cs; - * - * cs.x() = m_auxiliary_offset.y(); - * cs.y() = sqrt(1.0 - cs.x() * cs.x()); - * - * if (m_packed_data & sin_sign_mask) - * cs.y() = -cs.y(); - * - * offset = cs - * \endcode - * In addition, the source data for join is encoded as follows: - * \code - * float t; - * vec2 n0, n1; - * - * t = m_auxiliary_offset.x(); - * n0.x() = m_pre_offset.x(); - * n1.x() = m_pre_offset.y(); - * - * n0.y() = sqrt(1.0 - n0.x() * n0.x()); - * n1.y() = sqrt(1.0 - n1.x() * n1.x()); - * - * if (m_packed_data & normal0_y_sign_mask) - * n0.y() = -n0.y(); - * - * if (m_packed_data & normal1_y_sign_mask) - * n1.y() = -n1.y(); - * \endcode - * The vector n0 represents the normal of the path going into the join, - * the vector n1 represents the normal of the path going out of the join - * and t represents how much to interpolate from n0 to n1. - * - For those with offset_type() being \ref offset_miter_clip_join - * or \ref offset_miter_clip_join_lambda_negated - * the value is given by the following code - * \code - * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - * float r, det, lambda; - * det = dot(Jn1, n0); - * lambda = -t_sign(det); - * r = (det != 0.0) ? (dot(n0, n1) - 1.0) / det : 0.0; - * if (offset_type() == offset_miter_clip_join_lambda_negated) - * { - * lambda = -lambda; - * } - * //result: - * offset = lambda * (n + r * v); - * \endcode - * - For those with offset_type() being \ref offset_miter_join, - * or \ref offset_miter_bevel_join the value is given by the - * following code: - * \code - * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - * float lambda, r, d; - * lambda = t_sign(dot(Jn0, n1)); - * r = lambda / (1.0 + dot(n0, n1)); - * offset = r * (n0 + n1); - * \endcode - * - For those with offset_type() being \ref offset_rounded_cap, - * the value is given by the following code - * \code - * vec2 n(m_pre_offset), v(n.y(), -n.x()); - * offset = m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; - * \endcode - * - For those with offset_type() being \ref offset_square_cap, - * \ref offset_adjustable_cap_contour_start or - * \ref offset_adjustable_cap_contour_end the value the value - * is given by - * \code - * m_pre_offset + m_auxiliary_offset - * \endcode - * In addition, \ref m_auxiliary_offset the tangent vector along - * the path in the direction of the path and \ref m_pre_offset - * holds a vector perpindicular to the path or a zero vector - * (indicating it is not on boundary of cap). - */ - vec2 - offset_vector(void); - - /*! - * When offset_type() is one of \ref offset_miter_clip_join, - * \ref offset_miter_clip_join_lambda_negated, - * \ref offset_miter_bevel_join or \ref offset_miter_join, - * returns the distance to the miter point. For other point - * types, returns 0.0. - */ - float - miter_distance(void) const; - - /*! - * Pack the data of this \ref point into a \ref - * PainterAttribute. The packing is as follows: - * - PainterAttribute::m_attrib0 .xy -> point::m_position (float) - * - PainterAttribute::m_attrib0 .zw -> point::m_pre_offset (float) - * - PainterAttribute::m_attrib1 .x -> point::m_distance_from_edge_start (float) - * - PainterAttribute::m_attrib1 .y -> point::m_distance_from_contour_start (float) - * - PainterAttribute::m_attrib1 .zw -> point::m_auxiliary_offset (float) - * - PainterAttribute::m_attrib2 .x -> point::m_packed_data (uint) - * - PainterAttribute::m_attrib2 .y -> point::m_edge_length (float) - * - PainterAttribute::m_attrib2 .z -> point::m_open_contour_length (float) - * - PainterAttribute::m_attrib2 .w -> point::m_closed_contour_length (float) - * - * \param dst PainterAttribute to which to pack - */ - void - pack_point(PainterAttribute *dst) const; - - /*! - * Unpack a \ref point from a \ref PainterAttribute. - * \param dst point to which to unpack data - * \param src PainterAttribute from which to unpack data - */ - static - void - unpack_point(point *dst, const PainterAttribute &src); - }; + typedef StrokedPoint point; /*! * \brief diff --git a/inc/fastuidraw/painter/stroked_point.hpp b/inc/fastuidraw/painter/stroked_point.hpp new file mode 100644 index 000000000..d1d8341bc --- /dev/null +++ b/inc/fastuidraw/painter/stroked_point.hpp @@ -0,0 +1,565 @@ +/*! + * \file stroked_point.hpp + * \brief file stroked_point.hpp + * + * Copyright 2018 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + + +#pragma once + +#include +#include +#include + +namespace fastuidraw { + +/*!\addtogroup Paths + * @{ + */ + +/*! + * \brief + * A Stroked holds the data for a point of stroking. + * The data is so that changing the stroking width + * or miter limit does not change the stroking data. + */ +class StrokedPoint +{ +public: + /*! + * \brief + * Enumeration for specifing how to compute + * \ref offset_vector()). + */ + enum offset_type_t + { + /*! + * The point is for an edge of the path, + * point signifies the start of a sub-edge + * (quad) of drawing an edge. + */ + offset_start_sub_edge, + + /*! + * The point is for an edge of the path, + * point signifies the end of a sub-edge + * (quad) of drawing an edge. + */ + offset_end_sub_edge, + + /*! + * The point is at a position that has the + * same value as point on an edge but the + * point itself is part of a cap or join. + */ + offset_shared_with_edge, + + /*! + * The point is for a boundary point of a rounded join of the path + */ + offset_rounded_join, + + /*! + * Point type for miter-clip join point whose position + * depends on the miter-limit. + */ + offset_miter_clip_join, + + /*! + * Point type for miter-clip join point whose position + * depends on the miter-limit where the lambda of the + * computation is negatted. + */ + offset_miter_clip_join_lambda_negated, + + /*! + * Point type for miter-bevel join point whose position + * depends on the miter-limit. + */ + offset_miter_bevel_join, + + /*! + * Point type for miter join whose position depends on + * the miter-limit. + */ + offset_miter_join, + + /*! + * The point is for a boundary point of a rounded cap of the path + */ + offset_rounded_cap, + + /*! + * The point is for a boundary point of a square cap of the path + */ + offset_square_cap, + + /*! + * The point is from \ref adjustable_caps() point set. + * It is for a point for a cap at the start of a contour. + * These points are for dashed stroking with caps; they + * contain data to allow one from a vertex shader to extend + * or shrink the cap area correctly to implement dashed + * stroking. + */ + offset_adjustable_cap_contour_start, + + /*! + * The point is from \ref adjustable_caps() point set. + * It is for a point for a cap at the end of a contour. + * These points are for dashed stroking with caps; they + * contain data to allow one from a vertex shader to extend + * or shrink the cap area correctly to implement dashed + * stroking. + */ + offset_adjustable_cap_contour_end, + + /*! + * Number different point types with respect to rendering + */ + number_offset_types + }; + + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data + * common to all offset types. + */ + enum packed_data_bit_layout_common_t + { + /*! + * Bit0 for holding the offset_type() value + * of the point. + */ + offset_type_bit0 = 0, + + /*! + * number of bits needed to hold the + * offset_type() value of the point. + */ + offset_type_num_bits = 4, + + /*! + * Bit for holding boundary() value + * of the point + */ + boundary_bit = offset_type_bit0 + offset_type_num_bits, + + /*! + * Bit0 for holding the depth() value + * of the point + */ + depth_bit0, + + /*! + * number of bits needed to hold the + * depth() value of the point. + */ + depth_num_bits = 20, + + /*! + * Bit to indicate point is from a join. For these + * points, during dashed stroking, Painter does the + * check if a join should be drawn, as such when the + * bit is up encountered in a shader, the computation + * to check that it is drawn from dashing can be + * skipped and assume that fragments from such points + * are covered by the dash pattern. + */ + join_bit = depth_bit0 + depth_num_bits, + + /*! + * Number of bits used on common packed data + */ + number_common_bits, + }; + + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data + * for those with offset type \ref offset_rounded_join + */ + enum packed_data_bit_layout_rounded_join_t + { + /*! + * Bit for holding the the sign of + * the y-coordinate of the normal 0 + * for the offset_type() \ref + * offset_rounded_join. + */ + normal0_y_sign_bit = number_common_bits, + + /*! + * Bit for holding the the sign of + * the y-coordinate of the normal 1 + * for the offset_type() \ref + * offset_rounded_join. + */ + normal1_y_sign_bit, + + /*! + * Bit for holding the the sign of + * sin() value for the offset_type() + * \ref offset_rounded_join. + */ + sin_sign_bit, + }; + + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data for + * those with offset type \ref offset_adjustable_cap_contour_end + * or \ref offset_adjustable_cap_contour_start. + */ + enum packed_data_bit_adjustable_cap_t + { + /*! + * The bit is up if the point is for end of point + * of a cap (i.e. the side to be extended to make + * sure the entire cap near the end of edge is drawn). + */ + adjustable_cap_ending_bit = number_common_bits, + }; + + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data + * for those with offset type \ref offset_start_sub_edge + * or \ref offset_end_sub_edge. + */ + enum packed_data_bit_sub_edge_t + { + /*! + * The bit is up if the point is for the + * geometry of a bevel between two sub-edges. + */ + bevel_edge_bit = number_common_bits, + }; + + /*! + * \brief + * Enumeration holding bit masks generated from + * values in \ref packed_data_bit_layout_common_t, + * \ref packed_data_bit_layout_rounded_join_t, + * \ref packed_data_bit_adjustable_cap_t and \ref + * packed_data_bit_sub_edge_t. + */ + enum packed_data_bit_masks_t + { + /*! + * Mask generated for \ref offset_type_bit0 and + * \ref offset_type_num_bits + */ + offset_type_mask = FASTUIDRAW_MASK(offset_type_bit0, offset_type_num_bits), + + /*! + * Mask generated for \ref normal0_y_sign_bit + */ + normal0_y_sign_mask = FASTUIDRAW_MASK(normal0_y_sign_bit, 1), + + /*! + * Mask generated for \ref normal1_y_sign_bit + */ + normal1_y_sign_mask = FASTUIDRAW_MASK(normal1_y_sign_bit, 1), + + /*! + * Mask generated for \ref sin_sign_bit sin_sign_bit + */ + sin_sign_mask = FASTUIDRAW_MASK(sin_sign_bit, 1), + + /*! + * Mask generated for \ref boundary_bit + */ + boundary_mask = FASTUIDRAW_MASK(boundary_bit, 1), + + /*! + * Mask generated for \ref join_bit + */ + join_mask = FASTUIDRAW_MASK(join_bit, 1), + + /*! + * Mask generated for \ref adjustable_cap_ending_bit + */ + adjustable_cap_ending_mask = FASTUIDRAW_MASK(adjustable_cap_ending_bit, 1), + + /*! + * Mask generated for \ref bevel_edge_bit + */ + bevel_edge_mask = FASTUIDRAW_MASK(bevel_edge_bit, 1), + + /*! + * Mask generated for \ref depth_bit0 and \ref depth_num_bits + */ + depth_mask = FASTUIDRAW_MASK(depth_bit0, depth_num_bits), + }; + + /*! + * The base position of a point, taken directly from + * the TessellatedPath from which the + * StrokedPath is constructed. + */ + vec2 m_position; + + /*! + * Gives the offset vector used to help compute + * the point offset vector. + */ + vec2 m_pre_offset; + + /*! + * Provides an auxiliary offset data + */ + vec2 m_auxiliary_offset; + + /*! + * Gives the distance of the point from the start + * of the -edge- on which the point resides. + */ + float m_distance_from_edge_start; + + /*! + * Gives the distance of the point from the start + * of the -contour- on which the point resides. + */ + float m_distance_from_contour_start; + + /*! + * Gives the length of the edge on which the + * point lies. This value is the same for all + * points along a fixed edge. + */ + float m_edge_length; + + /*! + * Gives the length of the contour open on which + * the point lies. This value is the same for all + * points along a fixed contour. + */ + float m_open_contour_length; + + /*! + * Gives the length of the contour closed on which + * the point lies. This value is the same for all + * points along a fixed contour. + */ + float m_closed_contour_length; + + /*! + * Bit field with data packed as according to + * \ref packed_data_bit_layout_common_t, \ref + * packed_data_bit_layout_rounded_join_t, \ref + * packed_data_bit_adjustable_cap_t and \ref + * packed_data_bit_sub_edge_t. See also, + * \ref packed_data_bit_masks_t for bit masks + * generated. + */ + uint32_t m_packed_data; + + /*! + * Provides the point type from a value of \ref m_packed_data. + * The return value is one of the enumerations of + * \ref offset_type_t. + * \param packed_data_value value suitable for \ref m_packed_data + */ + static + enum offset_type_t + offset_type(uint32_t packed_data_value) + { + uint32_t v; + v = unpack_bits(offset_type_bit0, offset_type_num_bits, packed_data_value); + return static_cast(v); + } + + /*! + * Provides the point type for the point. The return value + * is one of the enumerations of \ref offset_type_t. + */ + enum offset_type_t + offset_type(void) const + { + return offset_type(m_packed_data); + } + + /*! + * When stroking the data, the depth test to only + * pass when the depth value is -strictly- larger + * so that a fixed pixel is not stroked twice by + * a single path. The value returned by depth() is + * a relative z-value for a vertex. The points + * drawn first have the largest z-values. + */ + uint32_t + depth(void) const + { + return unpack_bits(depth_bit0, depth_num_bits, m_packed_data); + } + + /*! + * Has value 0 or 1. If the value is 0, then + * the point is on the path. If the value has + * absolute value 1, then indicates a point that + * is on the boundary of the stroked path. The triangles + * produced from stroking are so that when + * on_boundary() is interpolated across the triangle + * the center of stroking the value is 0 and the + * value has value 1 on the boundary. + */ + int + on_boundary(void) const + { + return unpack_bits(boundary_bit, 1u, m_packed_data); + } + + /*! + * Computes the offset vector for a point. The final position + * of a point when stroking with a width of W is given by + * \code + * m_position + 0.5f * W * offset_vector(). + * \endcode + * The computation for offset_vector() is as follows. + * - For those with offset_type() being \ref offset_start_sub_edge, + * \ref offset_end_sub_edge and \ref offset_shared_with_edge, + * the offset is given by + * \code + * m_pre_offset + * \endcode + * In addition, for these offset types, \ref m_auxiliary_offset + * holds the the delta vector to the point on edge with + * which the point makes a quad. + * - For those with offset_type() being \ref offset_rounded_join, + * the value is given by the following code + * \code + * vec2 cs; + * + * cs.x() = m_auxiliary_offset.y(); + * cs.y() = sqrt(1.0 - cs.x() * cs.x()); + * + * if (m_packed_data & sin_sign_mask) + * cs.y() = -cs.y(); + * + * offset = cs + * \endcode + * In addition, the source data for join is encoded as follows: + * \code + * float t; + * vec2 n0, n1; + * + * t = m_auxiliary_offset.x(); + * n0.x() = m_pre_offset.x(); + * n1.x() = m_pre_offset.y(); + * + * n0.y() = sqrt(1.0 - n0.x() * n0.x()); + * n1.y() = sqrt(1.0 - n1.x() * n1.x()); + * + * if (m_packed_data & normal0_y_sign_mask) + * n0.y() = -n0.y(); + * + * if (m_packed_data & normal1_y_sign_mask) + * n1.y() = -n1.y(); + * \endcode + * The vector n0 represents the normal of the path going into the join, + * the vector n1 represents the normal of the path going out of the join + * and t represents how much to interpolate from n0 to n1. + * - For those with offset_type() being \ref offset_miter_clip_join + * or \ref offset_miter_clip_join_lambda_negated + * the value is given by the following code + * \code + * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); + * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); + * float r, det, lambda; + * det = dot(Jn1, n0); + * lambda = -t_sign(det); + * r = (det != 0.0) ? (dot(n0, n1) - 1.0) / det : 0.0; + * if (offset_type() == offset_miter_clip_join_lambda_negated) + * { + * lambda = -lambda; + * } + * //result: + * offset = lambda * (n + r * v); + * \endcode + * - For those with offset_type() being \ref offset_miter_join, + * or \ref offset_miter_bevel_join the value is given by the + * following code: + * \code + * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); + * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); + * float lambda, r, d; + * lambda = t_sign(dot(Jn0, n1)); + * r = lambda / (1.0 + dot(n0, n1)); + * offset = r * (n0 + n1); + * \endcode + * - For those with offset_type() being \ref offset_rounded_cap, + * the value is given by the following code + * \code + * vec2 n(m_pre_offset), v(n.y(), -n.x()); + * offset = m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; + * \endcode + * - For those with offset_type() being \ref offset_square_cap, + * \ref offset_adjustable_cap_contour_start or + * \ref offset_adjustable_cap_contour_end the value the value + * is given by + * \code + * m_pre_offset + m_auxiliary_offset + * \endcode + * In addition, \ref m_auxiliary_offset the tangent vector along + * the path in the direction of the path and \ref m_pre_offset + * holds a vector perpindicular to the path or a zero vector + * (indicating it is not on boundary of cap). + */ + vec2 + offset_vector(void); + + /*! + * When offset_type() is one of \ref offset_miter_clip_join, + * \ref offset_miter_clip_join_lambda_negated, + * \ref offset_miter_bevel_join or \ref offset_miter_join, + * returns the distance to the miter point. For other point + * types, returns 0.0. + */ + float + miter_distance(void) const; + + /*! + * Pack the data of this \ref point into a \ref + * PainterAttribute. The packing is as follows: + * - PainterAttribute::m_attrib0 .xy -> point::m_position (float) + * - PainterAttribute::m_attrib0 .zw -> point::m_pre_offset (float) + * - PainterAttribute::m_attrib1 .x -> point::m_distance_from_edge_start (float) + * - PainterAttribute::m_attrib1 .y -> point::m_distance_from_contour_start (float) + * - PainterAttribute::m_attrib1 .zw -> point::m_auxiliary_offset (float) + * - PainterAttribute::m_attrib2 .x -> point::m_packed_data (uint) + * - PainterAttribute::m_attrib2 .y -> point::m_edge_length (float) + * - PainterAttribute::m_attrib2 .z -> point::m_open_contour_length (float) + * - PainterAttribute::m_attrib2 .w -> point::m_closed_contour_length (float) + * + * \param dst PainterAttribute to which to pack + */ + void + pack_point(PainterAttribute *dst) const; + + /*! + * Unpack a \ref point from a \ref PainterAttribute. + * \param dst point to which to unpack data + * \param src PainterAttribute from which to unpack data + */ + static + void + unpack_point(StrokedPoint *dst, const PainterAttribute &src); +}; + + +/*! @} */ + +} diff --git a/src/fastuidraw/painter/Rules.mk b/src/fastuidraw/painter/Rules.mk index f1f90ba87..5769b363f 100644 --- a/src/fastuidraw/painter/Rules.mk +++ b/src/fastuidraw/painter/Rules.mk @@ -20,7 +20,7 @@ FASTUIDRAW_SOURCES += $(call filelist, fill_rule.cpp \ painter_shader.cpp painter_shader_set.cpp \ painter_dashed_stroke_shader_set.cpp painter_stroke_shader.cpp \ painter_glyph_shader.cpp painter_blend_shader_set.cpp \ - painter_fill_shader.cpp \ + painter_fill_shader.cpp stroked_point.cpp \ stroked_path.cpp filled_path.cpp) # Begin standard footer diff --git a/src/fastuidraw/painter/stroked_path.cpp b/src/fastuidraw/painter/stroked_path.cpp index 751c6373c..08d1c0a8b 100644 --- a/src/fastuidraw/painter/stroked_path.cpp +++ b/src/fastuidraw/painter/stroked_path.cpp @@ -3977,162 +3977,6 @@ fetch_create(float thresh, std::vector &values) } } -////////////////////////////////////// -// fastuidraw::StrokedPath::point methods -void -fastuidraw::StrokedPath::point:: -pack_point(PainterAttribute *dst) const -{ - dst->m_attrib0 = pack_vec4(m_position.x(), - m_position.y(), - m_pre_offset.x(), - m_pre_offset.y()); - - dst->m_attrib1 = pack_vec4(m_distance_from_edge_start, - m_distance_from_contour_start, - m_auxiliary_offset.x(), - m_auxiliary_offset.y()); - - dst->m_attrib2 = uvec4(m_packed_data, - pack_float(m_edge_length), - pack_float(m_open_contour_length), - pack_float(m_closed_contour_length)); -} - -void -fastuidraw::StrokedPath::point:: -unpack_point(point *dst, const PainterAttribute &a) -{ - dst->m_position.x() = unpack_float(a.m_attrib0.x()); - dst->m_position.y() = unpack_float(a.m_attrib0.y()); - - dst->m_pre_offset.x() = unpack_float(a.m_attrib0.z()); - dst->m_pre_offset.y() = unpack_float(a.m_attrib0.w()); - - dst->m_distance_from_edge_start = unpack_float(a.m_attrib1.x()); - dst->m_distance_from_contour_start = unpack_float(a.m_attrib1.y()); - dst->m_auxiliary_offset.x() = unpack_float(a.m_attrib1.z()); - dst->m_auxiliary_offset.y() = unpack_float(a.m_attrib1.w()); - - dst->m_packed_data = a.m_attrib2.x(); - dst->m_edge_length = unpack_float(a.m_attrib2.y()); - dst->m_open_contour_length = unpack_float(a.m_attrib2.z()); - dst->m_closed_contour_length = unpack_float(a.m_attrib2.w()); -} - -fastuidraw::vec2 -fastuidraw::StrokedPath::point:: -offset_vector(void) -{ - enum offset_type_t tp; - - tp = offset_type(); - - switch(tp) - { - case offset_start_sub_edge: - case offset_end_sub_edge: - case offset_shared_with_edge: - return m_pre_offset; - - case offset_square_cap: - return m_pre_offset + m_auxiliary_offset; - - case offset_rounded_cap: - { - vec2 n(m_pre_offset), v(n.y(), -n.x()); - return m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; - } - - case offset_miter_clip_join: - case offset_miter_clip_join_lambda_negated: - { - vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - float r, det, lambda; - - det = dot(Jn1, n0); - lambda = -t_sign(det); - r = (det != 0.0f) ? (dot(n0, n1) - 1.0f) / det : 0.0f; - - if (tp == offset_miter_clip_join_lambda_negated) - { - lambda = -lambda; - } - - return lambda * (n0 + r * Jn0); - } - - case offset_miter_bevel_join: - case offset_miter_join: - { - vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - float r, lambda, den; - - lambda = t_sign(dot(Jn0, n1)); - den = 1.0f + dot(n0, n1); - r = (den != 0.0f) ? lambda / den : 0.0f; - return r * (n0 + n1); - } - - case offset_rounded_join: - { - vec2 cs; - - cs.x() = m_auxiliary_offset.y(); - cs.y() = sqrt(1.0 - cs.x() * cs.x()); - if (m_packed_data & sin_sign_mask) - { - cs.y() = -cs.y(); - } - return cs; - } - - default: - return vec2(0.0f, 0.0f); - } -} - -float -fastuidraw::StrokedPath::point:: -miter_distance(void) const -{ - enum offset_type_t tp; - tp = offset_type(); - - switch(tp) - { - case offset_miter_clip_join: - case offset_miter_clip_join_lambda_negated: - { - vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - float r, det; - - det = dot(Jn1, n0); - r = (det != 0.0f) ? (dot(n0, n1) - 1.0f) / det : 0.0f; - return t_sqrt(1.0f + r * r); - } - - case offset_miter_bevel_join: - case offset_miter_join: - { - vec2 n0(m_pre_offset), n1(m_auxiliary_offset); - vec2 n0_plus_n1(n0 + n1); - float den; - - den = 1.0f + dot(n0, n1); - return den != 0.0f ? - n0_plus_n1.magnitude() / den : - 0.0f; - } - - default: - return 0.0f; - } -} - ////////////////////////////////////////////// // fastuidraw::StrokedPath::ScratchSpace methods fastuidraw::StrokedPath::ScratchSpace:: diff --git a/src/fastuidraw/painter/stroked_point.cpp b/src/fastuidraw/painter/stroked_point.cpp new file mode 100644 index 000000000..e13cb86f5 --- /dev/null +++ b/src/fastuidraw/painter/stroked_point.cpp @@ -0,0 +1,157 @@ +#include + +////////////////////////////////////// +// fastuidraw::StrokedPoint methods +void +fastuidraw::StrokedPoint:: +pack_point(PainterAttribute *dst) const +{ + dst->m_attrib0 = pack_vec4(m_position.x(), + m_position.y(), + m_pre_offset.x(), + m_pre_offset.y()); + + dst->m_attrib1 = pack_vec4(m_distance_from_edge_start, + m_distance_from_contour_start, + m_auxiliary_offset.x(), + m_auxiliary_offset.y()); + + dst->m_attrib2 = uvec4(m_packed_data, + pack_float(m_edge_length), + pack_float(m_open_contour_length), + pack_float(m_closed_contour_length)); +} + +void +fastuidraw::StrokedPoint:: +unpack_point(StrokedPoint *dst, const PainterAttribute &a) +{ + dst->m_position.x() = unpack_float(a.m_attrib0.x()); + dst->m_position.y() = unpack_float(a.m_attrib0.y()); + + dst->m_pre_offset.x() = unpack_float(a.m_attrib0.z()); + dst->m_pre_offset.y() = unpack_float(a.m_attrib0.w()); + + dst->m_distance_from_edge_start = unpack_float(a.m_attrib1.x()); + dst->m_distance_from_contour_start = unpack_float(a.m_attrib1.y()); + dst->m_auxiliary_offset.x() = unpack_float(a.m_attrib1.z()); + dst->m_auxiliary_offset.y() = unpack_float(a.m_attrib1.w()); + + dst->m_packed_data = a.m_attrib2.x(); + dst->m_edge_length = unpack_float(a.m_attrib2.y()); + dst->m_open_contour_length = unpack_float(a.m_attrib2.z()); + dst->m_closed_contour_length = unpack_float(a.m_attrib2.w()); +} + +fastuidraw::vec2 +fastuidraw::StrokedPoint:: +offset_vector(void) +{ + enum offset_type_t tp; + + tp = offset_type(); + + switch(tp) + { + case offset_start_sub_edge: + case offset_end_sub_edge: + case offset_shared_with_edge: + return m_pre_offset; + + case offset_square_cap: + return m_pre_offset + m_auxiliary_offset; + + case offset_rounded_cap: + { + vec2 n(m_pre_offset), v(n.y(), -n.x()); + return m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; + } + + case offset_miter_clip_join: + case offset_miter_clip_join_lambda_negated: + { + vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); + vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); + float r, det, lambda; + + det = dot(Jn1, n0); + lambda = -t_sign(det); + r = (det != 0.0f) ? (dot(n0, n1) - 1.0f) / det : 0.0f; + + if (tp == offset_miter_clip_join_lambda_negated) + { + lambda = -lambda; + } + + return lambda * (n0 + r * Jn0); + } + + case offset_miter_bevel_join: + case offset_miter_join: + { + vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); + vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); + float r, lambda, den; + + lambda = t_sign(dot(Jn0, n1)); + den = 1.0f + dot(n0, n1); + r = (den != 0.0f) ? lambda / den : 0.0f; + return r * (n0 + n1); + } + + case offset_rounded_join: + { + vec2 cs; + + cs.x() = m_auxiliary_offset.y(); + cs.y() = sqrt(1.0 - cs.x() * cs.x()); + if (m_packed_data & sin_sign_mask) + { + cs.y() = -cs.y(); + } + return cs; + } + + default: + return vec2(0.0f, 0.0f); + } +} + +float +fastuidraw::StrokedPoint:: +miter_distance(void) const +{ + enum offset_type_t tp; + tp = offset_type(); + + switch(tp) + { + case offset_miter_clip_join: + case offset_miter_clip_join_lambda_negated: + { + vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); + vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); + float r, det; + + det = dot(Jn1, n0); + r = (det != 0.0f) ? (dot(n0, n1) - 1.0f) / det : 0.0f; + return t_sqrt(1.0f + r * r); + } + + case offset_miter_bevel_join: + case offset_miter_join: + { + vec2 n0(m_pre_offset), n1(m_auxiliary_offset); + vec2 n0_plus_n1(n0 + n1); + float den; + + den = 1.0f + dot(n0, n1); + return den != 0.0f ? + n0_plus_n1.magnitude() / den : + 0.0f; + } + + default: + return 0.0f; + } +} From 9ce497b4488e6832a1845d0f57bc581293c29890 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 21:12:55 +0300 Subject: [PATCH 04/52] fastuidraw/painter/stroked_path: remove typedef of StrokedPoint to StrokedPath::point Change-Id: Ib9ee735d9210cbdb558dc260180afc8853036216 --- demos/painter_path_test/main.cpp | 4 +- demos/painter_test/main.cpp | 27 ++-- inc/fastuidraw/painter/stroked_path.hpp | 2 - src/fastuidraw/glsl/painter_backend_glsl.cpp | 54 +++---- src/fastuidraw/painter/stroked_path.cpp | 139 +++++++++---------- 5 files changed, 112 insertions(+), 114 deletions(-) diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index e83edd113..acf692bfc 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -1210,9 +1210,9 @@ per_path_processing(void) for(unsigned p = 0, endp = miter_points.size(); p < endp; ++p) { float v; - StrokedPath::point pt; + StrokedPoint pt; - StrokedPath::point::unpack_point(&pt, miter_points[p]); + StrokedPoint::unpack_point(&pt, miter_points[p]); v = pt.miter_distance(); if (std::isfinite(v)) { diff --git a/demos/painter_test/main.cpp b/demos/painter_test/main.cpp index ead38769f..a7e81676d 100644 --- a/demos/painter_test/main.cpp +++ b/demos/painter_test/main.cpp @@ -135,6 +135,7 @@ class painter_test:public sdl_painter_demo int main(int argc, char **argv) { + FASTUIDRAWassert(StrokedPoint::number_offset_types < FASTUIDRAW_MAX_VALUE_FROM_NUM_BITS(StrokedPoint::offset_type_num_bits)); std::cout << std::setw(40) << "header_size = " << PainterHeader::header_size << "\n" << std::setw(40) << "clip_equations_data_size = " << PainterClipEquations::clip_data_size << "\n" << std::setw(40) << "item_matrix_data_size = " << PainterItemMatrix::matrix_data_size << "\n" @@ -160,19 +161,19 @@ main(int argc, char **argv) << std::setw(40) << "transformation_translation_mask = " << bitset(PainterBrush::transformation_translation_mask) << "\n" << std::setw(40) << "transformation_matrix_mask = " << bitset(PainterBrush::transformation_matrix_mask) << "\n" - << std::setw(40) << "stroked_number_offset_types = " << StrokedPath::point::number_offset_types << "\n" - << std::setw(40) << "stroked_offset_type_bit0 = " << StrokedPath::point::offset_type_bit0 << "\n" - << std::setw(40) << "stroked_offset_type_num_bits = " << StrokedPath::point::offset_type_num_bits << "\n" - << std::setw(40) << "stroked_boundary_bit = " << StrokedPath::point::boundary_bit << "\n" - << std::setw(40) << "stroked_depth_bit0 = " << StrokedPath::point::depth_bit0 << "\n" - << std::setw(40) << "stroked_depth_num_bits = " << StrokedPath::point::depth_num_bits << "\n" - << std::setw(40) << "stroked_join_bit = " << StrokedPath::point::join_bit << "\n" - << std::setw(40) << "stroked_number_common_bits = " << StrokedPath::point::number_common_bits << "\n" - << std::setw(40) << "stroked_normal0_y_sign_bit = " << StrokedPath::point::normal0_y_sign_bit << "\n" - << std::setw(40) << "stroked_normal1_y_sign_bit = " << StrokedPath::point::normal1_y_sign_bit << "\n" - << std::setw(40) << "stroked_sin_sign_bit = " << StrokedPath::point::sin_sign_bit << "\n" - << std::setw(40) << "stroked_adjustable_cap_ending_bit = " << StrokedPath::point::adjustable_cap_ending_bit << "\n" - << std::setw(40) << "stroked_bevel_edge_bit = " << StrokedPath::point::bevel_edge_bit << "\n"; + << std::setw(40) << "stroked_number_offset_types = " << StrokedPoint::number_offset_types << "\n" + << std::setw(40) << "stroked_offset_type_bit0 = " << StrokedPoint::offset_type_bit0 << "\n" + << std::setw(40) << "stroked_offset_type_num_bits = " << StrokedPoint::offset_type_num_bits << "\n" + << std::setw(40) << "stroked_boundary_bit = " << StrokedPoint::boundary_bit << "\n" + << std::setw(40) << "stroked_depth_bit0 = " << StrokedPoint::depth_bit0 << "\n" + << std::setw(40) << "stroked_depth_num_bits = " << StrokedPoint::depth_num_bits << "\n" + << std::setw(40) << "stroked_join_bit = " << StrokedPoint::join_bit << "\n" + << std::setw(40) << "stroked_number_common_bits = " << StrokedPoint::number_common_bits << "\n" + << std::setw(40) << "stroked_normal0_y_sign_bit = " << StrokedPoint::normal0_y_sign_bit << "\n" + << std::setw(40) << "stroked_normal1_y_sign_bit = " << StrokedPoint::normal1_y_sign_bit << "\n" + << std::setw(40) << "stroked_sin_sign_bit = " << StrokedPoint::sin_sign_bit << "\n" + << std::setw(40) << "stroked_adjustable_cap_ending_bit = " << StrokedPoint::adjustable_cap_ending_bit << "\n" + << std::setw(40) << "stroked_bevel_edge_bit = " << StrokedPoint::bevel_edge_bit << "\n"; painter_test P; return P.main(argc, argv); diff --git a/inc/fastuidraw/painter/stroked_path.hpp b/inc/fastuidraw/painter/stroked_path.hpp index 3911e7f52..952c07a04 100644 --- a/inc/fastuidraw/painter/stroked_path.hpp +++ b/inc/fastuidraw/painter/stroked_path.hpp @@ -60,8 +60,6 @@ class StrokedPath: public reference_counted::non_concurrent { public: - typedef StrokedPoint point; - /*! * \brief * Opaque object to hold work room needed for functions diff --git a/src/fastuidraw/glsl/painter_backend_glsl.cpp b/src/fastuidraw/glsl/painter_backend_glsl.cpp index ec5fc467d..20d065d2a 100644 --- a/src/fastuidraw/glsl/painter_backend_glsl.cpp +++ b/src/fastuidraw/glsl/painter_backend_glsl.cpp @@ -493,34 +493,34 @@ add_enums(fastuidraw::glsl::ShaderSource &src) /* offset types for stroking. */ - .add_macro("fastuidraw_stroke_offset_start_sub_edge", StrokedPath::point::offset_start_sub_edge) - .add_macro("fastuidraw_stroke_offset_end_sub_edge", StrokedPath::point::offset_end_sub_edge) - .add_macro("fastuidraw_stroke_offset_shared_with_edge", StrokedPath::point::offset_shared_with_edge) - .add_macro("fastuidraw_stroke_offset_rounded_join", StrokedPath::point::offset_rounded_join) - - .add_macro("fastuidraw_stroke_offset_miter_bevel_join", StrokedPath::point::offset_miter_bevel_join) - .add_macro("fastuidraw_stroke_offset_miter_join", StrokedPath::point::offset_miter_join) - .add_macro("fastuidraw_stroke_offset_miter_clip_join", StrokedPath::point::offset_miter_clip_join) - .add_macro("fastuidraw_stroke_offset_miter_clip_join_lambda_negated", StrokedPath::point::offset_miter_clip_join_lambda_negated) - - .add_macro("fastuidraw_stroke_offset_rounded_cap", StrokedPath::point::offset_rounded_cap) - .add_macro("fastuidraw_stroke_offset_square_cap", StrokedPath::point::offset_square_cap) - .add_macro("fastuidraw_stroke_offset_adjustable_cap_contour_start", StrokedPath::point::offset_adjustable_cap_contour_start) - .add_macro("fastuidraw_stroke_offset_adjustable_cap_contour_end", StrokedPath::point::offset_adjustable_cap_contour_end) - .add_macro("fastuidraw_stroke_offset_type_bit0", StrokedPath::point::offset_type_bit0) - .add_macro("fastuidraw_stroke_offset_type_num_bits", StrokedPath::point::offset_type_num_bits) - - /* bit masks for StrokedPath::point::m_packed_data + .add_macro("fastuidraw_stroke_offset_start_sub_edge", StrokedPoint::offset_start_sub_edge) + .add_macro("fastuidraw_stroke_offset_end_sub_edge", StrokedPoint::offset_end_sub_edge) + .add_macro("fastuidraw_stroke_offset_shared_with_edge", StrokedPoint::offset_shared_with_edge) + .add_macro("fastuidraw_stroke_offset_rounded_join", StrokedPoint::offset_rounded_join) + + .add_macro("fastuidraw_stroke_offset_miter_bevel_join", StrokedPoint::offset_miter_bevel_join) + .add_macro("fastuidraw_stroke_offset_miter_join", StrokedPoint::offset_miter_join) + .add_macro("fastuidraw_stroke_offset_miter_clip_join", StrokedPoint::offset_miter_clip_join) + .add_macro("fastuidraw_stroke_offset_miter_clip_join_lambda_negated", StrokedPoint::offset_miter_clip_join_lambda_negated) + + .add_macro("fastuidraw_stroke_offset_rounded_cap", StrokedPoint::offset_rounded_cap) + .add_macro("fastuidraw_stroke_offset_square_cap", StrokedPoint::offset_square_cap) + .add_macro("fastuidraw_stroke_offset_adjustable_cap_contour_start", StrokedPoint::offset_adjustable_cap_contour_start) + .add_macro("fastuidraw_stroke_offset_adjustable_cap_contour_end", StrokedPoint::offset_adjustable_cap_contour_end) + .add_macro("fastuidraw_stroke_offset_type_bit0", StrokedPoint::offset_type_bit0) + .add_macro("fastuidraw_stroke_offset_type_num_bits", StrokedPoint::offset_type_num_bits) + + /* bit masks for StrokedPoint::m_packed_data */ - .add_macro("fastuidraw_stroke_sin_sign_mask", StrokedPath::point::sin_sign_mask) - .add_macro("fastuidraw_stroke_normal0_y_sign_mask", StrokedPath::point::normal0_y_sign_mask) - .add_macro("fastuidraw_stroke_normal1_y_sign_mask", StrokedPath::point::normal1_y_sign_mask) - .add_macro("fastuidraw_stroke_boundary_bit", StrokedPath::point::boundary_bit) - .add_macro("fastuidraw_stroke_join_mask", StrokedPath::point::join_mask) - .add_macro("fastuidraw_stroke_bevel_edge_mask", StrokedPath::point::bevel_edge_mask) - .add_macro("fastuidraw_stroke_adjustable_cap_ending_mask", StrokedPath::point::adjustable_cap_ending_mask) - .add_macro("fastuidraw_stroke_depth_bit0", StrokedPath::point::depth_bit0) - .add_macro("fastuidraw_stroke_depth_num_bits", StrokedPath::point::depth_num_bits) + .add_macro("fastuidraw_stroke_sin_sign_mask", StrokedPoint::sin_sign_mask) + .add_macro("fastuidraw_stroke_normal0_y_sign_mask", StrokedPoint::normal0_y_sign_mask) + .add_macro("fastuidraw_stroke_normal1_y_sign_mask", StrokedPoint::normal1_y_sign_mask) + .add_macro("fastuidraw_stroke_boundary_bit", StrokedPoint::boundary_bit) + .add_macro("fastuidraw_stroke_join_mask", StrokedPoint::join_mask) + .add_macro("fastuidraw_stroke_bevel_edge_mask", StrokedPoint::bevel_edge_mask) + .add_macro("fastuidraw_stroke_adjustable_cap_ending_mask", StrokedPoint::adjustable_cap_ending_mask) + .add_macro("fastuidraw_stroke_depth_bit0", StrokedPoint::depth_bit0) + .add_macro("fastuidraw_stroke_depth_num_bits", StrokedPoint::depth_num_bits) /* dash shader modes. */ diff --git a/src/fastuidraw/painter/stroked_path.cpp b/src/fastuidraw/painter/stroked_path.cpp index 08d1c0a8b..55fe8bcaf 100644 --- a/src/fastuidraw/painter/stroked_path.cpp +++ b/src/fastuidraw/painter/stroked_path.cpp @@ -37,27 +37,27 @@ namespace inline uint32_t pack_data(int on_boundary, - enum fastuidraw::StrokedPath::point::offset_type_t pt, + enum fastuidraw::StrokedPoint::offset_type_t pt, uint32_t depth) { using namespace fastuidraw; FASTUIDRAWassert(on_boundary == 0 || on_boundary == 1); uint32_t bb(on_boundary), pp(pt); - return pack_bits(StrokedPath::point::offset_type_bit0, - StrokedPath::point::offset_type_num_bits, pp) - | pack_bits(StrokedPath::point::boundary_bit, 1u, bb) - | pack_bits(StrokedPath::point::depth_bit0, - StrokedPath::point::depth_num_bits, depth); + return pack_bits(StrokedPoint::offset_type_bit0, + StrokedPoint::offset_type_num_bits, pp) + | pack_bits(StrokedPoint::boundary_bit, 1u, bb) + | pack_bits(StrokedPoint::depth_bit0, + StrokedPoint::depth_num_bits, depth); } inline uint32_t pack_data_join(int on_boundary, - enum fastuidraw::StrokedPath::point::offset_type_t pt, + enum fastuidraw::StrokedPoint::offset_type_t pt, uint32_t depth) { - return pack_data(on_boundary, pt, depth) | fastuidraw::StrokedPath::point::join_mask; + return pack_data(on_boundary, pt, depth) | fastuidraw::StrokedPoint::join_mask; } void @@ -1111,7 +1111,7 @@ namespace mutable std::vector m_n0, m_n1; }; - template + template class MiterJoinCreator:public JoinCreatorBase { public: @@ -1301,7 +1301,7 @@ namespace static void pack_fan(bool entering_contour, - enum fastuidraw::StrokedPath::point::offset_type_t type, + enum fastuidraw::StrokedPoint::offset_type_t type, const fastuidraw::TessellatedPath::point &edge_pt, const fastuidraw::vec2 &stroking_normal, unsigned int depth, @@ -1399,8 +1399,8 @@ namespace PreparedAttributeData m_bevel_joins; PreparedAttributeData m_miter_clip_joins; - PreparedAttributeData > m_miter_joins; - PreparedAttributeData > m_miter_bevel_joins; + PreparedAttributeData > m_miter_joins; + PreparedAttributeData > m_miter_bevel_joins; PreparedAttributeData m_square_caps; PreparedAttributeData m_adjustable_caps; @@ -2347,8 +2347,8 @@ build_chunk(const EdgeRanges &edge, { for(unsigned int v = edge.m_vertex_data_range.m_begin; v < edge.m_vertex_data_range.m_end; ++v) { - fastuidraw::StrokedPath::point P; - fastuidraw::StrokedPath::point::unpack_point(&P, attribute_data[v]); + fastuidraw::StrokedPoint P; + fastuidraw::StrokedPoint::unpack_point(&P, attribute_data[v]); FASTUIDRAWassert(P.depth() >= edge.m_depth_range.m_begin); FASTUIDRAWassert(P.depth() < edge.m_depth_range.m_end); } @@ -2365,7 +2365,7 @@ process_sub_edge(const SingleSubEdge &sub_edge, unsigned int depth, { const int boundary_values[3] = { 1, 1, 0 }; const float normal_sign[3] = { 1.0f, -1.0f, 0.0f }; - fastuidraw::vecN pts; + fastuidraw::vecN pts; if (sub_edge.m_has_bevel) { @@ -2386,20 +2386,20 @@ process_sub_edge(const SingleSubEdge &sub_edge, unsigned int depth, } pts[0].m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pts[0].m_packed_data = pack_data(0, fastuidraw::StrokedPath::point::offset_start_sub_edge, depth) - | fastuidraw::StrokedPath::point::bevel_edge_mask; + pts[0].m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_start_sub_edge, depth) + | fastuidraw::StrokedPoint::bevel_edge_mask; pts[1].m_pre_offset = sub_edge.m_bevel_lambda * sub_edge.m_bevel_normal; - pts[1].m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_start_sub_edge, depth) - | fastuidraw::StrokedPath::point::bevel_edge_mask; + pts[1].m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_start_sub_edge, depth) + | fastuidraw::StrokedPoint::bevel_edge_mask; pts[2].m_pre_offset = sub_edge.m_bevel_lambda * sub_edge.m_normal; - pts[2].m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_start_sub_edge, depth) - | fastuidraw::StrokedPath::point::bevel_edge_mask; + pts[2].m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_start_sub_edge, depth) + | fastuidraw::StrokedPoint::bevel_edge_mask; for(unsigned int i = 0; i < 3; ++i) { - pts[i].fastuidraw::StrokedPath::point::pack_point(&attribute_data[vert_offset + i]); + pts[i].fastuidraw::StrokedPoint::pack_point(&attribute_data[vert_offset + i]); } vert_offset += 3; @@ -2428,7 +2428,7 @@ process_sub_edge(const SingleSubEdge &sub_edge, unsigned int depth, pts[k].m_pre_offset = normal_sign[k] * sub_edge.m_normal; pts[k].m_auxiliary_offset = sub_edge.m_delta; pts[k].m_packed_data = pack_data(boundary_values[k], - fastuidraw::StrokedPath::point::offset_start_sub_edge, + fastuidraw::StrokedPoint::offset_start_sub_edge, depth); pts[k + 3].m_position = sub_edge.m_pt1.m_pt; @@ -2440,13 +2440,13 @@ process_sub_edge(const SingleSubEdge &sub_edge, unsigned int depth, pts[k + 3].m_pre_offset = normal_sign[k] * sub_edge.m_normal; pts[k + 3].m_auxiliary_offset = -sub_edge.m_delta; pts[k + 3].m_packed_data = pack_data(boundary_values[k], - fastuidraw::StrokedPath::point::offset_end_sub_edge, + fastuidraw::StrokedPoint::offset_end_sub_edge, depth); } for(unsigned int i = 0; i < 6; ++i) { - pts[i].fastuidraw::StrokedPath::point::pack_point(&attribute_data[vert_offset + i]); + pts[i].fastuidraw::StrokedPoint::pack_point(&attribute_data[vert_offset + i]); } indices[index_offset + 0] = vert_offset + 0; @@ -2881,7 +2881,7 @@ add_data(unsigned int depth, { unsigned int i, first; float theta; - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; first = vertex_offset; @@ -2893,7 +2893,7 @@ add_data(unsigned int depth, pt.m_open_contour_length = m_open_contour_length; pt.m_closed_contour_length = m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -2905,7 +2905,7 @@ add_data(unsigned int depth, pt.m_open_contour_length = m_open_contour_length; pt.m_closed_contour_length = m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -2927,21 +2927,21 @@ add_data(unsigned int depth, pt.m_edge_length = m_edge_length; pt.m_open_contour_length = m_open_contour_length; pt.m_closed_contour_length = m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_rounded_join, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_rounded_join, depth); if (m_lambda * m_n0.y() < 0.0f) { - pt.m_packed_data |= fastuidraw::StrokedPath::point::normal0_y_sign_mask; + pt.m_packed_data |= fastuidraw::StrokedPoint::normal0_y_sign_mask; } if (m_lambda * m_n1.y() < 0.0f) { - pt.m_packed_data |= fastuidraw::StrokedPath::point::normal1_y_sign_mask; + pt.m_packed_data |= fastuidraw::StrokedPoint::normal1_y_sign_mask; } if (cs_as_complex.imag() < 0.0f) { - pt.m_packed_data |= fastuidraw::StrokedPath::point::sin_sign_mask; + pt.m_packed_data |= fastuidraw::StrokedPoint::sin_sign_mask; } pt.pack_point(&pts[vertex_offset]); } @@ -2954,7 +2954,7 @@ add_data(unsigned int depth, pt.m_open_contour_length = m_open_contour_length; pt.m_closed_contour_length = m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3053,7 +3053,7 @@ fill_join_implement(unsigned int join_id, { const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; CommonJoinData J(prev_pt.m_p, m_n0[join_id], next_pt.m_p, m_n1[join_id], @@ -3073,7 +3073,7 @@ fill_join_implement(unsigned int join_id, pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset + 0]); pt.m_position = J.m_p0; @@ -3084,7 +3084,7 @@ fill_join_implement(unsigned int join_id, pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset + 1]); pt.m_position = J.m_p1; @@ -3095,7 +3095,7 @@ fill_join_implement(unsigned int join_id, pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset + 2]); add_triangle_fan(vertex_offset, vertex_offset + 3, indices, index_offset); @@ -3146,7 +3146,7 @@ fill_join_implement(unsigned int join_id, const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; unsigned int first; CommonJoinData J(prev_pt.m_p, m_n0[join_id], @@ -3194,7 +3194,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3207,7 +3207,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3220,7 +3220,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_miter_clip_join, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3233,7 +3233,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_miter_clip_join_lambda_negated, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join_lambda_negated, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3246,7 +3246,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3255,7 +3255,7 @@ fill_join_implement(unsigned int join_id, //////////////////////////////////// // MiterJoinCreator methods -template +template MiterJoinCreator:: MiterJoinCreator(const PathData &P, const StrokedPathSubset *st): @@ -3264,7 +3264,7 @@ MiterJoinCreator(const PathData &P, post_ctor_initalize(); } -template +template void MiterJoinCreator:: add_join(unsigned int join_id, @@ -3284,7 +3284,7 @@ add_join(unsigned int join_id, m_n1.push_back(leaving_join.m_begin_normal); } -template +template void MiterJoinCreator:: fill_join_implement(unsigned int join_id, @@ -3299,7 +3299,7 @@ fill_join_implement(unsigned int join_id, const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; unsigned int first; CommonJoinData J(prev_pt.m_p, m_n0[join_id], @@ -3347,7 +3347,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3360,7 +3360,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3386,7 +3386,7 @@ fill_join_implement(unsigned int join_id, pt.m_edge_length = J.m_edge_length; pt.m_open_contour_length = J.m_open_contour_length; pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3572,7 +3572,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, CommonCapData C(is_starting_cap, p.m_p, normal_from_stroking); unsigned int first, i; float theta; - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; first = vertex_offset; @@ -3584,7 +3584,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_distance_from_contour_start = p.m_distance_from_contour_start; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3596,7 +3596,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3614,7 +3614,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_edge_length = p.m_edge_length; pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_rounded_cap, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_rounded_cap, depth); pt.pack_point(&pts[vertex_offset]); } @@ -3626,7 +3626,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3665,7 +3665,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, { CommonCapData C(is_starting_cap, p.m_p, normal_from_stroking); unsigned int first; - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; first = vertex_offset; @@ -3677,7 +3677,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(0, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3689,7 +3689,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3701,7 +3701,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = C.m_v; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_square_cap, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3713,7 +3713,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = C.m_v; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_square_cap, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3725,7 +3725,7 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPath::point::offset_shared_with_edge, depth); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3751,7 +3751,7 @@ compute_size(const ContourData &P) void AdjustableCapCreator:: pack_fan(bool entering_contour, - enum fastuidraw::StrokedPath::point::offset_type_t type, + enum fastuidraw::StrokedPoint::offset_type_t type, const fastuidraw::TessellatedPath::point &p, const fastuidraw::vec2 &stroking_normal, unsigned int depth, @@ -3762,7 +3762,7 @@ pack_fan(bool entering_contour, { CommonCapData C(entering_contour, p.m_p, stroking_normal); unsigned int first(vertex_offset); - fastuidraw::StrokedPath::point pt; + fastuidraw::StrokedPoint pt; pt.m_position = C.m_p; pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); @@ -3796,7 +3796,7 @@ pack_fan(bool entering_contour, pt.m_edge_length = p.m_edge_length; pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPath::point::adjustable_cap_ending_mask; + pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3808,7 +3808,7 @@ pack_fan(bool entering_contour, pt.m_edge_length = p.m_edge_length; pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(0, type, depth) | fastuidraw::StrokedPath::point::adjustable_cap_ending_mask; + pt.m_packed_data = pack_data(0, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3820,7 +3820,7 @@ pack_fan(bool entering_contour, pt.m_edge_length = p.m_edge_length; pt.m_open_contour_length = p.m_open_contour_length; pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPath::point::adjustable_cap_ending_mask; + pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; pt.pack_point(&pts[vertex_offset]); ++vertex_offset; @@ -3849,10 +3849,10 @@ add_cap(const fastuidraw::vec2 &normal_from_stroking, unsigned int &vertex_offset, unsigned int &index_offset) const { - enum fastuidraw::StrokedPath::point::offset_type_t tp; + enum fastuidraw::StrokedPoint::offset_type_t tp; tp = (is_starting_cap) ? - fastuidraw::StrokedPath::point::offset_adjustable_cap_contour_start : - fastuidraw::StrokedPath::point::offset_adjustable_cap_contour_end; + fastuidraw::StrokedPoint::offset_adjustable_cap_contour_start : + fastuidraw::StrokedPoint::offset_adjustable_cap_contour_end; pack_fan(is_starting_cap, tp, p0, normal_from_stroking, depth, @@ -4108,7 +4108,6 @@ cap_chunks(void) const fastuidraw::StrokedPath:: StrokedPath(const fastuidraw::TessellatedPath &P) { - FASTUIDRAWassert(point::number_offset_types < FASTUIDRAW_MAX_VALUE_FROM_NUM_BITS(point::offset_type_num_bits)); m_d = FASTUIDRAWnew StrokedPathPrivate(P); } From 83e041a60f73801c1d4b1bbf34b1e94c941040ca Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 22:07:46 +0300 Subject: [PATCH 05/52] demos/painter_path_test: draw glyphs in reversed-y because glyphs have coordinates of y-incrasing upwards Change-Id: I148f48ce7e42f3ecadaf7bcc8ebed5f2d2673bbe --- demos/painter_path_test/main.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index acf692bfc..468c30ecf 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -127,10 +127,11 @@ class PerPath { public: PerPath(const Path &path, const std::string &label, - int w, int h); + int w, int h, bool from_gylph); Path m_path; std::string m_label; + bool m_from_glyph; unsigned int m_fill_rule; unsigned int m_end_fill_rule; vec2 m_shear, m_shear2; @@ -339,9 +340,10 @@ class painter_stroke_test:public sdl_painter_demo /////////////////////////////////// // PerPath methods PerPath:: -PerPath(const Path &path, const std::string &label, int w, int h): +PerPath(const Path &path, const std::string &label, int w, int h, bool from_gylph): m_path(path), m_label(label), + m_from_glyph(from_gylph), m_fill_rule(PainterEnums::odd_even_fill_rule), m_end_fill_rule(PainterEnums::fill_rule_data_count), m_shear(1.0f, 1.0f), @@ -1135,7 +1137,7 @@ construct_paths(int w, int h) read_path(P, buffer.str()); if (P.number_contours() > 0) { - m_paths.push_back(PerPath(P, file, w, h)); + m_paths.push_back(PerPath(P, file, w, h, false)); } } } @@ -1152,7 +1154,7 @@ construct_paths(int w, int h) { std::ostringstream str; str << "character code:" << character_code; - m_paths.push_back(PerPath(g.path(), str.str(), w, h)); + m_paths.push_back(PerPath(g.path(), str.str(), w, h, true)); } } @@ -1181,7 +1183,7 @@ construct_paths(int w, int h) << Path::contour_end() << vec2(300.0f, 300.0f) << Path::contour_end(); - m_paths.push_back(PerPath(path, "Default Path", w, h)); + m_paths.push_back(PerPath(path, "Default Path", w, h, false)); } } @@ -1410,6 +1412,18 @@ draw_frame(void) */ m_painter->shear(shear2().x(), shear2().y()); + if (m_paths[m_selected_path].m_from_glyph) + { + /* Glyphs have y-increasing upwards, rather than + * downwards; so we reverse the y + */ + float y; + y = path().tessellation()->bounding_box_min().y() + + path().tessellation()->bounding_box_max().y(); + m_painter->translate(vec2(0.0f, y)); + m_painter->shear(1.0f, -1.0f); + } + if (m_clipping_window) { if (m_clip_window_path_dirty) From 10c6738239690ab9d9acb643ae275d081d44cc9b Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 25 Apr 2018 22:36:58 +0300 Subject: [PATCH 06/52] demos/painter_path_test: make coordinates per-path Change-Id: Id2657af11d15220b7771ed632d53e5d22aabd190 --- demos/painter_path_test/main.cpp | 270 +++++++++++++++++++++---------- 1 file changed, 182 insertions(+), 88 deletions(-) diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index 468c30ecf..7e341d988 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -135,7 +135,20 @@ class PerPath unsigned int m_fill_rule; unsigned int m_end_fill_rule; vec2 m_shear, m_shear2; + float m_angle; PanZoomTrackerSDLEvent m_path_zoomer; + + bool m_translate_brush, m_matrix_brush; + + vec2 m_gradient_p0, m_gradient_p1; + float m_gradient_r0, m_gradient_r1; + bool m_repeat_gradient; + + bool m_repeat_window; + vec2 m_repeat_xy, m_repeat_wh; + + bool m_clipping_window; + vec2 m_clipping_xy, m_clipping_wh; }; class painter_stroke_test:public sdl_painter_demo @@ -235,6 +248,90 @@ class painter_stroke_test:public sdl_painter_demo return m_paths[m_selected_path].m_shear2; } + float& + angle(void) + { + return m_paths[m_selected_path].m_angle; + } + + vec2& + gradient_p0(void) + { + return m_paths[m_selected_path].m_gradient_p0; + } + + vec2& + gradient_p1(void) + { + return m_paths[m_selected_path].m_gradient_p1; + } + + float& + gradient_r0(void) + { + return m_paths[m_selected_path].m_gradient_r0; + } + + float& + gradient_r1(void) + { + return m_paths[m_selected_path].m_gradient_r1; + } + + bool& + repeat_gradient(void) + { + return m_paths[m_selected_path].m_repeat_gradient; + } + + bool& + translate_brush(void) + { + return m_paths[m_selected_path].m_translate_brush; + } + + bool& + matrix_brush(void) + { + return m_paths[m_selected_path].m_matrix_brush; + } + + bool& + repeat_window(void) + { + return m_paths[m_selected_path].m_repeat_window; + } + + vec2& + repeat_xy(void) + { + return m_paths[m_selected_path].m_repeat_xy; + } + + vec2& + repeat_wh(void) + { + return m_paths[m_selected_path].m_repeat_wh; + } + + bool& + clipping_window(void) + { + return m_paths[m_selected_path].m_clipping_window; + } + + vec2& + clipping_xy(void) + { + return m_paths[m_selected_path].m_clipping_xy; + } + + vec2& + clipping_wh(void) + { + return m_paths[m_selected_path].m_clipping_wh; + } + command_line_argument_value m_change_miter_limit_rate; command_line_argument_value m_change_stroke_width_rate; command_line_argument_value m_window_change_rate; @@ -303,22 +400,11 @@ class painter_stroke_test:public sdl_painter_demo bool m_draw_fill, m_aa_fill_by_stroking; unsigned int m_active_color_stop; unsigned int m_gradient_draw_mode; - bool m_repeat_gradient; unsigned int m_image_filter; bool m_draw_stats; float m_curve_flatness; bool m_print_submit_stroke_time, m_print_submit_fill_time; - vec2 m_gradient_p0, m_gradient_p1; - float m_gradient_r0, m_gradient_r1; - bool m_translate_brush, m_matrix_brush; - - bool m_repeat_window; - vec2 m_repeat_xy, m_repeat_wh; - - bool m_clipping_window; - vec2 m_clipping_xy, m_clipping_wh; - bool m_with_aa; bool m_wire_frame; bool m_stroke_width_in_pixels; @@ -327,8 +413,6 @@ class painter_stroke_test:public sdl_painter_demo bool m_fill_by_clipping; bool m_draw_grid; - float m_angle; - simple_time m_draw_timer, m_fps_timer; Path m_grid_path; bool m_grid_path_dirty; @@ -347,7 +431,13 @@ PerPath(const Path &path, const std::string &label, int w, int h, bool from_gylp m_fill_rule(PainterEnums::odd_even_fill_rule), m_end_fill_rule(PainterEnums::fill_rule_data_count), m_shear(1.0f, 1.0f), - m_shear2(1.0f, 1.0f) + m_shear2(1.0f, 1.0f), + m_angle(0.0f), + m_translate_brush(false), + m_matrix_brush(false), + m_repeat_gradient(true), + m_repeat_window(false), + m_clipping_window(false) { m_end_fill_rule = m_path.tessellation()->filled()->subset(0).winding_numbers().size() + PainterEnums::fill_rule_data_count; @@ -368,6 +458,18 @@ PerPath(const Path &path, const std::string &label, int w, int h, bool from_gylp sc.scale( 1.0f / mm); tr2.translation(dsp * 0.5f); m_path_zoomer.transformation(tr2 * sc * tr1); + + m_gradient_p0 = p0; + m_gradient_p1 = p1; + + m_gradient_r0 = 0.0f; + m_gradient_r1 = 200.0f / m_path_zoomer.transformation().scale(); + + m_repeat_xy = vec2(0.0f, 0.0f); + m_repeat_wh = m_path.tessellation()->bounding_box_max() - m_path.tessellation()->bounding_box_min(); + + m_clipping_xy = m_path.tessellation()->bounding_box_min(); + m_clipping_wh = m_repeat_wh; } ////////////////////////////////////// @@ -434,20 +536,14 @@ painter_stroke_test(void): m_draw_fill(false), m_aa_fill_by_stroking(false), m_active_color_stop(0), m_gradient_draw_mode(draw_no_gradient), - m_repeat_gradient(true), m_image_filter(image_nearest_filter), m_draw_stats(false), - m_translate_brush(false), - m_matrix_brush(false), - m_repeat_window(false), - m_clipping_window(false), m_with_aa(true), m_wire_frame(false), m_stroke_width_in_pixels(false), m_force_square_viewport(false), m_fill_by_clipping(false), m_draw_grid(false), - m_angle(0.0f), m_grid_path_dirty(true), m_clip_window_path_dirty(true) { @@ -568,13 +664,13 @@ update_cts_params(void) if (keyboard_state[SDL_SCANCODE_9]) { - m_angle += speed * 0.1f; - std::cout << "Angle set to: " << m_angle << "\n"; + angle() += speed * 0.1f; + std::cout << "Angle set to: " << angle() << "\n"; } if (keyboard_state[SDL_SCANCODE_0]) { - m_angle -= speed * 0.1f; - std::cout << "Angle set to: " << m_angle << "\n"; + angle() -= speed * 0.1f; + std::cout << "Angle set to: " << angle() << "\n"; } speed_stroke = speed * m_change_stroke_width_rate.m_value; @@ -601,7 +697,7 @@ update_cts_params(void) std::cout << "Stroke width set to: " << m_stroke_width << "\n"; } - if (m_repeat_window) + if (repeat_window()) { vec2 *changer; float delta, delta_y; @@ -609,12 +705,12 @@ update_cts_params(void) delta = m_window_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL]) { - changer = &m_repeat_wh; + changer = &repeat_wh(); delta_y = delta; } else { - changer = &m_repeat_xy; + changer = &repeat_xy(); delta_y = -delta; } @@ -644,7 +740,7 @@ update_cts_params(void) if (keyboard_state[SDL_SCANCODE_UP] || keyboard_state[SDL_SCANCODE_DOWN] || keyboard_state[SDL_SCANCODE_RIGHT] || keyboard_state[SDL_SCANCODE_LEFT]) { - std::cout << "Brush repeat window set to: xy = " << m_repeat_xy << " wh = " << m_repeat_wh << "\n"; + std::cout << "Brush repeat window set to: xy = " << repeat_xy() << " wh = " << repeat_wh() << "\n"; } } @@ -656,30 +752,30 @@ update_cts_params(void) delta = m_radial_gradient_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_1]) { - m_gradient_r0 -= delta; - m_gradient_r0 = fastuidraw::t_max(0.0f, m_gradient_r0); + gradient_r0() -= delta; + gradient_r0() = fastuidraw::t_max(0.0f, gradient_r0()); } if (keyboard_state[SDL_SCANCODE_2]) { - m_gradient_r0 += delta; + gradient_r0() += delta; } if (keyboard_state[SDL_SCANCODE_3]) { - m_gradient_r1 -= delta; - m_gradient_r1 = fastuidraw::t_max(0.0f, m_gradient_r1); + gradient_r1() -= delta; + gradient_r1() = fastuidraw::t_max(0.0f, gradient_r1()); } if (keyboard_state[SDL_SCANCODE_4]) { - m_gradient_r1 += delta; + gradient_r1() += delta; } if (keyboard_state[SDL_SCANCODE_1] || keyboard_state[SDL_SCANCODE_2] || keyboard_state[SDL_SCANCODE_3] || keyboard_state[SDL_SCANCODE_4]) { std::cout << "Radial gradient values set to: r0 = " - << m_gradient_r0 << " r1 = " << m_gradient_r1 << "\n"; + << gradient_r0() << " r1 = " << gradient_r1() << "\n"; } } @@ -703,7 +799,7 @@ update_cts_params(void) } } - if (m_clipping_window) + if (clipping_window()) { vec2 *changer; float delta, delta_y; @@ -711,12 +807,12 @@ update_cts_params(void) delta = m_window_change_rate.m_value * speed / zoomer().transformation().scale(); if (keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL]) { - changer = &m_clipping_wh; + changer = &clipping_wh(); delta_y = delta; } else { - changer = &m_clipping_xy; + changer = &clipping_xy(); delta_y = -delta; } @@ -744,13 +840,11 @@ update_cts_params(void) || keyboard_state[SDL_SCANCODE_KP_6] || keyboard_state[SDL_SCANCODE_KP_8]) { m_clip_window_path_dirty = true; - std::cout << "Clipping window set to: xy = " << m_clipping_xy << " wh = " << m_clipping_wh << "\n"; + std::cout << "Clipping window set to: xy = " << clipping_xy() << " wh = " << clipping_wh() << "\n"; } } } - - vec2 painter_stroke_test:: brush_item_coordinate(ivec2 scr) @@ -758,12 +852,12 @@ brush_item_coordinate(ivec2 scr) vec2 p; p = item_coordinates(scr); - if (m_matrix_brush) + if (matrix_brush()) { p *= zoomer().transformation().scale(); } - if (m_translate_brush) + if (translate_brush()) { p += zoomer().transformation().translation(); } @@ -784,11 +878,11 @@ item_coordinates(ivec2 scr) */ p /= shear(); - /* unapply rotation by m_angle + /* unapply rotation by angle() */ float s, c, a; float2x2 tr; - a = -m_angle * M_PI / 180.0f; + a = -angle() * M_PI / 180.0f; s = t_sin(a); c = t_cos(a); @@ -803,6 +897,17 @@ item_coordinates(ivec2 scr) */ p /= shear2(); + /* unapply glyph-flip + */ + if (m_paths[m_selected_path].m_from_glyph) + { + float y; + y = path().tessellation()->bounding_box_min().y() + + path().tessellation()->bounding_box_max().y(); + p.y() -= y; + p.y() *= -1.0f; + } + return p; } @@ -832,11 +937,11 @@ handle_event(const SDL_Event &ev) if (ev.motion.state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) { - m_gradient_p0 = brush_item_coordinate(c); + gradient_p0() = brush_item_coordinate(c); } else if (ev.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT)) { - m_gradient_p1 = brush_item_coordinate(c); + gradient_p1() = brush_item_coordinate(c); } } break; @@ -851,6 +956,7 @@ handle_event(const SDL_Event &ev) case SDLK_k: cycle_value(m_selected_path, ev.key.keysym.mod & (KMOD_SHIFT|KMOD_CTRL|KMOD_ALT), m_paths.size()); std::cout << "Path " << m_paths[m_selected_path].m_label << " selected\n"; + m_clip_window_path_dirty = true; break; case SDLK_a: @@ -903,30 +1009,30 @@ handle_event(const SDL_Event &ev) break; case SDLK_o: - m_clipping_window = !m_clipping_window; - std::cout << "Clipping window: " << on_off(m_clipping_window) << "\n"; + clipping_window() = !clipping_window(); + std::cout << "Clipping window: " << on_off(clipping_window()) << "\n"; break; case SDLK_w: - m_repeat_window = !m_repeat_window; - std::cout << "Brush Repeat window: " << on_off(m_repeat_window) << "\n"; + repeat_window() = !repeat_window(); + std::cout << "Brush Repeat window: " << on_off(repeat_window()) << "\n"; break; case SDLK_y: - m_matrix_brush = !m_matrix_brush; - std::cout << "Matrix brush: " << on_off(m_matrix_brush) << "\n"; + matrix_brush() = !matrix_brush(); + std::cout << "Matrix brush: " << on_off(matrix_brush()) << "\n"; break; case SDLK_t: - m_translate_brush = !m_translate_brush; - std::cout << "Translate brush: " << on_off(m_translate_brush) << "\n"; + translate_brush() = !translate_brush(); + std::cout << "Translate brush: " << on_off(translate_brush()) << "\n"; break; case SDLK_h: if (m_gradient_draw_mode != draw_no_gradient) { - m_repeat_gradient = !m_repeat_gradient; - if (!m_repeat_gradient) + repeat_gradient() = !repeat_gradient(); + if (!repeat_gradient()) { std::cout << "non-"; } @@ -1406,7 +1512,7 @@ draw_frame(void) /* apply rotation */ - m_painter->rotate(m_angle * M_PI / 180.0f); + m_painter->rotate(angle() * M_PI / 180.0f); /* apply shear2 */ @@ -1424,15 +1530,15 @@ draw_frame(void) m_painter->shear(1.0f, -1.0f); } - if (m_clipping_window) + if (clipping_window()) { if (m_clip_window_path_dirty) { Path clip_window_path; - clip_window_path << m_clipping_xy - << vec2(m_clipping_xy.x(), m_clipping_xy.y() + m_clipping_wh.y()) - << m_clipping_xy + m_clipping_wh - << vec2(m_clipping_xy.x() + m_clipping_wh.x(), m_clipping_xy.y()) + clip_window_path << clipping_xy() + << vec2(clipping_xy().x(), clipping_xy().y() + clipping_wh().y()) + << clipping_xy() + clipping_wh() + << vec2(clipping_xy().x() + clipping_wh().x(), clipping_xy().y()) << Path::contour_end(); m_clip_window_path.swap(clip_window_path); m_clip_window_path_dirty = false; @@ -1450,7 +1556,7 @@ draw_frame(void) PainterEnums::miter_clip_joins, false); m_painter->restore(); - m_painter->clipInRect(m_clipping_xy, m_clipping_wh); + m_painter->clipInRect(clipping_xy(), clipping_wh()); } @@ -1461,7 +1567,7 @@ draw_frame(void) fill_brush.pen(m_fill_red.m_value, m_fill_green.m_value, m_fill_blue.m_value, m_fill_alpha.m_value); - if (m_translate_brush) + if (translate_brush()) { fill_brush.transformation_translate(zoomer().transformation().translation()); } @@ -1470,7 +1576,7 @@ draw_frame(void) fill_brush.no_transformation_translation(); } - if (m_matrix_brush) + if (matrix_brush()) { float2x2 m; m(0, 0) = m(1, 1) = zoomer().transformation().scale(); @@ -1481,9 +1587,9 @@ draw_frame(void) fill_brush.no_transformation_matrix(); } - if (m_repeat_window) + if (repeat_window()) { - fill_brush.repeat_window(m_repeat_xy, m_repeat_wh); + fill_brush.repeat_window(repeat_xy(), repeat_wh()); } else { @@ -1493,14 +1599,14 @@ draw_frame(void) if (m_gradient_draw_mode == draw_linear_gradient) { fill_brush.linear_gradient(m_color_stops[m_active_color_stop].second, - m_gradient_p0, m_gradient_p1, m_repeat_gradient); + gradient_p0(), gradient_p1(), repeat_gradient()); } else if (m_gradient_draw_mode == draw_radial_gradient) { fill_brush.radial_gradient(m_color_stops[m_active_color_stop].second, - m_gradient_p0, m_gradient_r0, - m_gradient_p1, m_gradient_r1, - m_repeat_gradient); + gradient_p0(), gradient_r0(), + gradient_p1(), gradient_r1(), + repeat_gradient()); } else { @@ -1668,16 +1774,16 @@ draw_frame(void) r0 = 15.0f * inv_scale; r1 = 30.0f * inv_scale; - p0 = m_gradient_p0; - p1 = m_gradient_p1; + p0 = gradient_p0(); + p1 = gradient_p1(); - if (m_translate_brush) + if (translate_brush()) { p0 -= zoomer().transformation().translation(); p1 -= zoomer().transformation().translation(); } - if (m_matrix_brush) + if (matrix_brush()) { p0 *= inv_scale; p1 *= inv_scale; @@ -1816,18 +1922,6 @@ derived_init(int w, int h) } } - m_gradient_p0 = item_coordinates(ivec2(0, 0)); - m_gradient_p1 = item_coordinates(ivec2(w, h)); - - m_gradient_r0 = 0.0f; - m_gradient_r1 = 200.0f / zoomer().transformation().scale(); - - m_repeat_xy = vec2(0.0f, 0.0f); - m_repeat_wh = path().tessellation()->bounding_box_max() - path().tessellation()->bounding_box_min(); - - m_clipping_xy = path().tessellation()->bounding_box_min(); - m_clipping_wh = m_repeat_wh; - m_curve_flatness = m_painter->curveFlatness(); m_print_submit_stroke_time = true; m_print_submit_fill_time = true; From 2552d883f5434455f9c56dbcffc392145167b03e Mon Sep 17 00:00:00 2001 From: Yucheng Zhang Date: Thu, 26 Apr 2018 12:50:20 +0800 Subject: [PATCH 07/52] README.md: fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e7f9f869..a501a8fd2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Fast UI Draw ============ -Fast UI Draw in a library that provides a higher performance Canvas interface. +Fast UI Draw is a library that provides a higher performance Canvas interface. It is designed so that it always draws using a GPU. In contrast to many common implementations of Canvas drawing, Fast UI Draw From 1b2646b44c3282789678e050a9ab7a6f4b9604b8 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Thu, 26 Apr 2018 10:41:19 +0300 Subject: [PATCH 08/52] fastuidraw/path: remove time parameter from tessellate() and rely on implicit ordering Change-Id: I85e42a3553a9373fde1c2f8a26cb30f69c62dd63 --- inc/fastuidraw/path.hpp | 11 ++-- src/fastuidraw/path.cpp | 122 ++++++++++++++++------------------------ 2 files changed, 53 insertions(+), 80 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 78cbe5668..ab7dbb356 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -224,10 +224,9 @@ class PathContour: * that the region is the entire interpolator. * \param out_regionA location to which to write the first half * \param out_regionB location to which to write the second half - * \param out_t location to which to write the time (parameter) for - * in the middle of in_region * \param out_p location to which to write the position of the point - * on the curve in the middle of in_region + * on the curve in the middle (with repsect to time) of + * in_region * \param out_threshholds location to which to write the threshholds * the tessellation achieved; array is indexed * by \ref TessellatedPath::threshhold_type_t. @@ -241,8 +240,7 @@ class PathContour: void tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - float *out_t, vec2 *out_p, - c_array out_threshholds) const = 0; + vec2 *out_p, c_array out_threshholds) const = 0; }; /*! @@ -292,8 +290,7 @@ class PathContour: void tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - float *out_t, vec2 *out_p, - c_array out_threshholds) const; + vec2 *out_p, c_array out_threshholds) const; virtual void approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const; diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 60a18b5a3..0168e67c1 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -28,20 +28,6 @@ namespace { - class analytic_point_data:public fastuidraw::TessellatedPath::point - { - public: - analytic_point_data(float t, const fastuidraw::vec2 &p); - - bool - operator<(const analytic_point_data &rhs) const - { - return m_time < rhs.m_time; - } - - float m_time; - }; - inline float compute_distance(const fastuidraw::vec2 &a, @@ -82,8 +68,7 @@ namespace private: void - tessellation_worker(unsigned int idx_p, unsigned int idx_q, - unsigned int recursion_level, + tessellation_worker(unsigned int recurse_level, fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, fastuidraw::c_array out_threshholds); @@ -100,15 +85,17 @@ namespace } void - complete_threshholds(unsigned int idx_start, - unsigned int idx_mid, - unsigned int idx_end, - fastuidraw::c_array out_threshholds); + add_point(const fastuidraw::vec2 &pt) + { + fastuidraw::TessellatedPath::point P; + P.m_p = pt; + m_data.push_back(P); + } const fastuidraw::PathContour::interpolator_generic *m_h; fastuidraw::TessellatedPath::TessellationParams m_thresh; unsigned int m_max_recursion, m_max_size; - std::vector m_data; + std::vector m_data; }; class InterpolatorBasePrivate @@ -343,15 +330,6 @@ namespace }; } -//////////////////////////////////// -// analytic_point_data methods -analytic_point_data:: -analytic_point_data(float t, const fastuidraw::vec2 &p): - m_time(t) -{ - m_p = p; -} - ///////////////////////////////// // Tessellator methods unsigned int @@ -388,16 +366,14 @@ Tessellator:: fill_data(fastuidraw::c_array out_data, fastuidraw::c_array out_threshholds) { - /* initialize m_data with start and end point data. + /* + * tessellate: note that we add the start point, then tessellate + * and then at the end add the end point. By doing so, the points + * are added to m_data in order of time automatically. */ - m_data.push_back(analytic_point_data(0.0f, m_h->start_pt())); - m_data.push_back(analytic_point_data(1.0f, m_h->end_pt())); - - /* tessellate */ - tessellation_worker(0, 1, 0, nullptr, out_threshholds); - - /* sort the values by time */ - std::sort(m_data.begin(), m_data.end()); + add_point(m_h->start_pt()); + tessellation_worker(0, nullptr, out_threshholds); + add_point(m_h->end_pt()); FASTUIDRAWassert(m_data.size() <= out_data.size()); std::copy(m_data.begin(), m_data.end(), out_data.begin()); @@ -406,54 +382,56 @@ fill_data(fastuidraw::c_array out_data, void Tessellator:: -complete_threshholds(unsigned int idx_start, - unsigned int idx_mid, - unsigned int idx_end, - fastuidraw::c_array out_threshholds) -{ - using namespace fastuidraw; - - FASTUIDRAWassert(out_threshholds[TessellatedPath::threshhold_curve_distance] >= 0.0f); - FASTUIDRAWunused(idx_start); - FASTUIDRAWunused(idx_mid); - FASTUIDRAWunused(idx_end); - FASTUIDRAWunused(out_threshholds); -} - -void -Tessellator:: -tessellation_worker(unsigned int idx_start, unsigned int idx_end, - unsigned int recurse_level, +tessellation_worker(unsigned int recurse_level, fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, fastuidraw::c_array out_threshholds) { using namespace fastuidraw; - unsigned int idx_mid(m_data.size()); - PathContour::interpolator_generic::tessellated_region *rgnA, *rgnB; - vec2 p;; - float t; + PathContour::interpolator_generic::tessellated_region *rgnA(nullptr); + PathContour::interpolator_generic::tessellated_region *rgnB(nullptr); + vec2 p; - m_h->tessellate(in_src, &rgnA, &rgnB, - &t, &p, out_threshholds); - - complete_threshholds(idx_start, idx_mid, idx_end, out_threshholds); - m_data.push_back(analytic_point_data(t, p)); + m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshholds); if (recurse_level + 1u < m_max_recursion && !tessellation_satsified(recurse_level, out_threshholds)) { vecN tmpA(-1.0f), tmpB(-1.0f); - tessellation_worker(idx_start, idx_mid, recurse_level + 1, rgnA, tmpA); - tessellation_worker(idx_mid, idx_end, recurse_level + 1, rgnB, tmpB); + + /* NOTE the order of recursing and adding to m_data: + * - first we recurse into the left side + * - second we add the mid-point + * - last we recurse into the right side + * By doing so, we keep the order in time of the points, + * since all points on the left side come before the + * mid point, and all points in the right side come + * after the midpoint. + */ + tessellation_worker(recurse_level + 1, rgnA, tmpA); + add_point(p); + tessellation_worker(recurse_level + 1, rgnB, tmpB); + for (unsigned int i = 0; i < TessellatedPath::number_threshholds; ++i) { out_threshholds[i] = t_max(tmpA[i], tmpB[i]); } } + else + { + add_point(p); + } - FASTUIDRAWdelete(rgnA); - FASTUIDRAWdelete(rgnB); + + if (rgnA) + { + FASTUIDRAWdelete(rgnA); + } + + if (rgnB) + { + FASTUIDRAWdelete(rgnB); + } } //////////////////////////////////////// @@ -634,8 +612,7 @@ void fastuidraw::PathContour::bezier:: tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - float *out_t, vec2 *out_p, - c_array out_threshholds) const + vec2 *out_p, c_array out_threshholds) const { BezierPrivate *d; d = static_cast(m_d); @@ -689,7 +666,6 @@ tessellate(tessellated_region *in_region, *out_regionA = newA; *out_regionB = newB; - *out_t = newA->m_end; *out_p = newA->m_pts.back(); out_threshholds[TessellatedPath::threshhold_curve_distance] From e7d9c4ccffc326e37945e6abb78d7f8d65bad6ea Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Thu, 26 Apr 2018 16:15:29 +0300 Subject: [PATCH 09/52] faastuidraw/painter/filled_path: better name for field Change-Id: I74b9e677a5d65bab55e3a4028097236c6b14adf6 --- src/fastuidraw/painter/filled_path.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/fastuidraw/painter/filled_path.cpp b/src/fastuidraw/painter/filled_path.cpp index 577c156d5..dba657b24 100644 --- a/src/fastuidraw/painter/filled_path.cpp +++ b/src/fastuidraw/painter/filled_path.cpp @@ -151,7 +151,7 @@ namespace { public: unsigned int m_start, m_end, m_next; - bool m_draw_edge, m_draw_bevel; + bool m_draw_edge, m_draw_join; unsigned int num_attributes(void) const @@ -159,7 +159,7 @@ namespace unsigned int e, b; e = (m_draw_edge) ? 4 : 0; - b = (m_draw_bevel) ? 3 : 0; + b = (m_draw_join) ? 3 : 0; return e + b; } @@ -169,7 +169,7 @@ namespace unsigned int e, b; e = (m_draw_edge) ? 6 : 0; - b = (m_draw_bevel) ? 3 : 0; + b = (m_draw_join) ? 3 : 0; return e + b; } }; @@ -1128,7 +1128,7 @@ add_edge(unsigned int p0, unsigned int p1, bool edge_drawn) { FASTUIDRAWassert(m_current.back().m_end == p0); m_current.back().m_next = p1; - m_current.back().m_draw_bevel = edge_drawn || m_current.back().m_draw_edge; + m_current.back().m_draw_join = edge_drawn || m_current.back().m_draw_edge; } E.m_start = p0; @@ -1148,11 +1148,11 @@ end_boundary(void) FASTUIDRAWassert(m_current.back().m_end == m_current.front().m_start); m_current.back().m_next = m_current.front().m_end; - m_current.back().m_draw_bevel = m_current.front().m_draw_edge || m_current.back().m_draw_edge; + m_current.back().m_draw_join = m_current.front().m_draw_edge || m_current.back().m_draw_edge; for(const Edge &e : m_current) { - if (e.m_draw_edge || e.m_draw_bevel) + if (e.m_draw_edge || e.m_draw_join) { m_edges.push_back(e); ++m_edge_count; @@ -2474,7 +2474,7 @@ fill_data(fastuidraw::c_array attributes, fastuidraw::c_array dst_attrib; fastuidraw::c_array dst_index; unsigned int num_attribute, num_indices; - unsigned int start_bevel_idx(0), start_bevel_attr(0); + unsigned int start_join_idx(0), start_join_attr(0); num_attribute = E.num_attributes(); num_indices = E.num_indices(); @@ -2494,15 +2494,15 @@ fill_data(fastuidraw::c_array attributes, dst_index[4] = a_tmp[ch] + 2; dst_index[5] = a_tmp[ch] + 3; - start_bevel_idx = 6; - start_bevel_attr = 4; + start_join_idx = 6; + start_join_attr = 4; } - if (E.m_draw_bevel) + if (E.m_draw_join) { for (unsigned int i = 0; i < 3; ++i) { - dst_index[start_bevel_idx + i] = a_tmp[ch] + start_bevel_attr + i; + dst_index[start_join_idx + i] = a_tmp[ch] + start_join_attr + i; } } @@ -2532,7 +2532,7 @@ pack_attribute(const Edge &E, -1.0f }; - FASTUIDRAWassert(E.m_draw_bevel || E.m_draw_edge); + FASTUIDRAWassert(E.m_draw_join || E.m_draw_edge); if (E.m_draw_edge) { @@ -2548,7 +2548,7 @@ pack_attribute(const Edge &E, } } - if (E.m_draw_bevel) + if (E.m_draw_join) { float s; fastuidraw::dvec2 t2, n2, p; From 664b7e5ce37e92986d56bc12c99b525b13f84479 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Thu, 26 Apr 2018 17:04:23 +0300 Subject: [PATCH 10/52] fastuidraw/painter: remove having seperate shader for pixel-unit stroking Instead of having a dedicated shader (and function calls too!) for stroking when radius/width of stroking is in pixel units, have that embedded in PainterStrokeParams/PainterDashedStrokeParams by encoding that with the sign of the stroking radius/width. --- demos/common/sdl_painter_demo.cpp | 6 -- demos/painter_glyph_test/main.cpp | 26 +++----- demos/painter_path_test/main.cpp | 59 +++++++---------- inc/fastuidraw/painter/painter.hpp | 43 ------------ .../painter/painter_dashed_stroke_params.hpp | 29 +++++--- inc/fastuidraw/painter/painter_shader_set.hpp | 32 --------- .../painter/painter_stroke_params.hpp | 48 ++++++++++++-- .../glsl/private/backend_shaders.cpp | 49 +++++--------- .../glsl/private/backend_shaders.hpp | 6 +- ...w_painter_stroke.vert.glsl.resource_string | 10 +-- .../painter/packing/painter_backend.cpp | 2 - src/fastuidraw/painter/painter.cpp | 22 ------- .../painter/painter_dashed_stroke_params.cpp | 52 +++++++++++---- src/fastuidraw/painter/painter_shader_set.cpp | 6 -- .../painter/painter_stroke_params.cpp | 66 +++++++++++++------ 15 files changed, 205 insertions(+), 251 deletions(-) diff --git a/demos/common/sdl_painter_demo.cpp b/demos/common/sdl_painter_demo.cpp index 99987157a..416660041 100644 --- a/demos/common/sdl_painter_demo.cpp +++ b/demos/common/sdl_painter_demo.cpp @@ -630,15 +630,9 @@ init_gl(int w, int h) std::cout << "\tSolid StrokeShaders:\n"; print_stroke_shader_ids(sh.stroke_shader()); - std::cout << "\tPixel Width Stroke Shaders:\n"; - print_stroke_shader_ids(sh.pixel_width_stroke_shader()); - std::cout << "\tDashed Stroke Shader:\n"; print_dashed_stroke_shader_ids(sh.dashed_stroke_shader()); - std::cout << "\tPixel Width Dashed Stroke Shader:\n"; - print_dashed_stroke_shader_ids(sh.pixel_width_dashed_stroke_shader()); - std::cout << "\tFill Shader:" << sh.fill_shader().item_shader()->tag() << "\n"; } diff --git a/demos/painter_glyph_test/main.cpp b/demos/painter_glyph_test/main.cpp index ef6130fdf..37869762a 100644 --- a/demos/painter_glyph_test/main.cpp +++ b/demos/painter_glyph_test/main.cpp @@ -702,6 +702,10 @@ draw_frame(void) PainterStrokeParams st; st.miter_limit(5.0f); st.width(m_stroke_width); + if (m_pixel_width_stroking) + { + st.stroking_units(PainterStrokeParams::pixel_stroking_units); + } src = m_current_drawer; @@ -731,22 +735,12 @@ draw_frame(void) //path, thus we also need to negate in the y-direction. m_painter->shear(sc, -sc); - if (m_pixel_width_stroking) - { - m_painter->stroke_path_pixel_width(PainterData(pst, pbr), - glyphs[i].path(), - true, PainterEnums::flat_caps, - static_cast(m_join_style), - m_anti_alias_path_stroking); - } - else - { - m_painter->stroke_path(PainterData(pst, pbr), - glyphs[i].path(), - true, PainterEnums::flat_caps, - static_cast(m_join_style), - m_anti_alias_path_stroking); - } + m_painter->stroke_path(PainterData(pst, pbr), + glyphs[i].path(), + true, PainterEnums::flat_caps, + static_cast(m_join_style), + m_anti_alias_path_stroking); + m_painter->restore(); } } diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index 7e341d988..280ad0458 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -1675,13 +1675,16 @@ draw_frame(void) if (m_aa_fill_by_stroking && m_with_aa) { PainterStrokeParams st; - st.miter_limit(-1.0f); - st.width(2.0f); - m_painter->stroke_path_pixel_width(PainterData(&fill_brush, &st), - path(), true, - PainterEnums::flat_caps, - PainterEnums::bevel_joins, - true); + st + .miter_limit(-1.0f) + .width(2.0f) + .stroking_units(PainterStrokeParams::pixel_stroking_units); + + m_painter->stroke_path(PainterData(&fill_brush, &st), + path(), true, + PainterEnums::flat_caps, + PainterEnums::bevel_joins, + true); } submit_fill_time = measure.elapsed_us(); } @@ -1713,23 +1716,16 @@ draw_frame(void) c_array dash_ptr(&m_dash_patterns[D][0], m_dash_patterns[D].size()); st.dash_pattern(dash_ptr); - if (m_stroke_width_in_pixels) { - m_painter->stroke_dashed_path_pixel_width(PainterData(m_stroke_pen, &st), - path(), m_close_contour, - static_cast(m_cap_style), - static_cast(m_join_style), - m_with_aa); - } - else - { - m_painter->stroke_dashed_path(PainterData(m_stroke_pen, &st), - path(), m_close_contour, - static_cast(m_cap_style), - static_cast(m_join_style), - m_with_aa); + st.stroking_units(PainterStrokeParams::pixel_stroking_units); } + + m_painter->stroke_dashed_path(PainterData(m_stroke_pen, &st), + path(), m_close_contour, + static_cast(m_cap_style), + static_cast(m_join_style), + m_with_aa); } else { @@ -1743,23 +1739,16 @@ draw_frame(void) st.miter_limit(-1.0f); } st.width(m_stroke_width); - if (m_stroke_width_in_pixels) { - m_painter->stroke_path_pixel_width(PainterData(m_stroke_pen, &st), - path(), m_close_contour, - static_cast(m_cap_style), - static_cast(m_join_style), - m_with_aa); - } - else - { - m_painter->stroke_path(PainterData(m_stroke_pen, &st), - path(), m_close_contour, - static_cast(m_cap_style), - static_cast(m_join_style), - m_with_aa); + st.stroking_units(PainterStrokeParams::pixel_stroking_units); } + + m_painter->stroke_path(PainterData(m_stroke_pen, &st), + path(), m_close_contour, + static_cast(m_cap_style), + static_cast(m_join_style), + m_with_aa); } submit_stroke_time = measure.elapsed_us(); } diff --git a/inc/fastuidraw/painter/painter.hpp b/inc/fastuidraw/painter/painter.hpp index 95803211c..32a98e22a 100644 --- a/inc/fastuidraw/painter/painter.hpp +++ b/inc/fastuidraw/painter/painter.hpp @@ -493,28 +493,6 @@ namespace fastuidraw bool with_shader_based_anti_aliasing, const reference_counted_ptr &call_back = reference_counted_ptr()); - /*! - * Stroke a path using PainterShaderSet::pixel_width_stroke_shader() - * of default_shaders(). - * \param draw data for how to draw - * \param path Path to stroke - * \param close_contours if true, draw the closing edges (and joins) of each contour - * of the path - * \param cp cap style - * \param js join style - * \param with_shader_based_anti_aliasing draw the path in two passes using shader - * based anti-aliasing; one should NEVER - * have this as true if the surface passed - * in begin() is a multi-sampled surface - * \param call_back if non-nullptr handle, call back called when attribute data - * is added. - */ - void - stroke_path_pixel_width(const PainterData &draw, const Path &path, - bool close_contours, enum PainterEnums::cap_style cp, enum PainterEnums::join_style js, - bool with_shader_based_anti_aliasing, - const reference_counted_ptr &call_back = reference_counted_ptr()); - /*! * Stroke a path dashed. * \param shader shader with which to draw @@ -584,27 +562,6 @@ namespace fastuidraw bool with_shader_based_anti_aliasing, const reference_counted_ptr &call_back = reference_counted_ptr()); - /*! - * Stroke a path using PainterShaderSet::pixel_width_dashed_stroke_shader() of default_shaders(). - * \param draw data for how to draw - * \param path Path to stroke - * \param close_contours if true, draw the closing edges (and joins) of each contour - * of the path - * \param cp cap style - * \param js join style - * \param with_shader_based_anti_aliasing draw the path in two passes using shader - * based anti-aliasing; one should NEVER - * have this as true if the surface passed - * in begin() is a multi-sampled surface - * \param call_back if non-nullptr handle, call back called when attribute data - * is added. - */ - void - stroke_dashed_path_pixel_width(const PainterData &draw, const Path &path, - bool close_contours, enum PainterEnums::cap_style cp, enum PainterEnums::join_style js, - bool with_shader_based_anti_aliasing, - const reference_counted_ptr &call_back = reference_counted_ptr()); - /*! * Fill a path. * \param shader shader with which to fill the attribute data diff --git a/inc/fastuidraw/painter/painter_dashed_stroke_params.hpp b/inc/fastuidraw/painter/painter_dashed_stroke_params.hpp index 692b596a6..f43fd71c4 100644 --- a/inc/fastuidraw/painter/painter_dashed_stroke_params.hpp +++ b/inc/fastuidraw/painter/painter_dashed_stroke_params.hpp @@ -19,6 +19,7 @@ #pragma once #include +#include #include namespace fastuidraw @@ -117,10 +118,12 @@ namespace fastuidraw width(void) const; /*! - * Set the value of width(void) const + * Set the value of width(void) const, + * values are clamped to be non-negative. */ PainterDashedStrokeParams& width(float f); + /*! * The stroking radius, equivalent to * \code @@ -140,6 +143,20 @@ namespace fastuidraw PainterDashedStrokeParams& radius(float f); + /*! + * Returns the units of the stroking, default value is + * \ref PainterStrokeParams::path_stroking_units + */ + enum PainterStrokeParams::stroking_units_t + stroking_units(void) const; + + /*! + * Set the value of stroking_units(void) const, + * values are clamped to be non-negative. + */ + PainterDashedStrokeParams& + stroking_units(enum PainterStrokeParams::stroking_units_t); + /*! * The dashed offset, i.e. the starting point of the * dash pattern to start dashed stroking. @@ -169,16 +186,10 @@ namespace fastuidraw /*! * Constructs and returns a DashEvaluator compatible * with the data of PainterDashedStrokeParams. - * \param pixel_width_stroking if true return an object to - * be used when stroking width - * is in pixels; if false return - * an object to be used when - * stroking width is in coordinates - * of the path. */ static reference_counted_ptr - dash_evaluator(bool pixel_width_stroking); + dash_evaluator(void); /*! * Returns a StrokingDataSelectorBase suitable for @@ -186,7 +197,7 @@ namespace fastuidraw */ static reference_counted_ptr - stroking_data_selector(bool pixel_width_stroking); + stroking_data_selector(void); }; /*! @} */ diff --git a/inc/fastuidraw/painter/painter_shader_set.hpp b/inc/fastuidraw/painter/painter_shader_set.hpp index 2bce859db..c6998e4db 100644 --- a/inc/fastuidraw/painter/painter_shader_set.hpp +++ b/inc/fastuidraw/painter/painter_shader_set.hpp @@ -112,22 +112,6 @@ namespace fastuidraw PainterShaderSet& stroke_shader(const PainterStrokeShader &sh); - /*! - * Shader set for stroking of paths where the stroking - * width is given in pixels. The stroking parameters are - * given by PainterStrokeParams. - */ - const PainterStrokeShader& - pixel_width_stroke_shader(void) const; - - /*! - * Set the value returned by - * pixel_width_stroke_shader(void) const. - * \param sh value to use - */ - PainterShaderSet& - pixel_width_stroke_shader(const PainterStrokeShader &sh); - /*! * Shader set for stroking of paths where the stroking * width is given in same units as the original path. @@ -143,22 +127,6 @@ namespace fastuidraw PainterShaderSet& dashed_stroke_shader(const PainterDashedStrokeShaderSet &sh); - /*! - * Shader set for stroking of paths where the stroking - * width is given in pixels. The stroking parameters are - * given by PainterStrokeParams. - */ - const PainterDashedStrokeShaderSet& - pixel_width_dashed_stroke_shader(void) const; - - /*! - * Set the value returned by - * pixel_width_stroke_shader(void) const. - * \param sh value to use - */ - PainterShaderSet& - pixel_width_dashed_stroke_shader(const PainterDashedStrokeShaderSet &sh); - /*! * Shader for filling of paths. */ diff --git a/inc/fastuidraw/painter/painter_stroke_params.hpp b/inc/fastuidraw/painter/painter_stroke_params.hpp index 04af11ddb..49bed2928 100644 --- a/inc/fastuidraw/painter/painter_stroke_params.hpp +++ b/inc/fastuidraw/painter/painter_stroke_params.hpp @@ -35,6 +35,24 @@ namespace fastuidraw class PainterStrokeParams:public PainterItemShaderData { public: + /*! + * \brief + * Enumeration to specify the units of the stroking radius + */ + enum stroking_units_t + { + /*! + * Indicates that the stroking units is in local + * coordinates of the Path being stroking + */ + path_stroking_units, + + /*! + * Indicates that the stroking units are in pixels + */ + pixel_stroking_units, + }; + /*! * \brief * Enumeration that provides offsets for the stroking @@ -42,7 +60,14 @@ namespace fastuidraw */ enum stroke_data_offset_t { - stroke_radius_offset, /*!< offset to stroke radius (packed as float) */ + /*! + * Offset to stroke radius (packed as float). + * The absolute value gives the stroking radius, + * if teh value is negative then the stroking radius + * is in units of pixels, if positive it is in local + * path coordinates. + */ + stroke_radius_offset, stroke_miter_limit_offset, /*!< offset to stroke miter limit (packed as float) */ stroke_data_size /*!< size of data for stroking*/ @@ -66,13 +91,14 @@ namespace fastuidraw miter_limit(float f); /*! - * The stroking width + * The stroking width, always non-negative */ float width(void) const; /*! - * Set the value of width(void) const + * Set the value of width(void) const, + * values are clamped to be non-negative. */ PainterStrokeParams& width(float f); @@ -96,13 +122,27 @@ namespace fastuidraw PainterStrokeParams& radius(float f); + /*! + * Returns the units of the stroking, default value is + * \ref path_stroking_units + */ + enum stroking_units_t + stroking_units(void) const; + + /*! + * Set the value of stroking_units(void) const, + * values are clamped to be non-negative. + */ + PainterStrokeParams& + stroking_units(enum stroking_units_t); + /*! * Returns a StrokingDataSelectorBase suitable for * PainterStrokeParams */ static reference_counted_ptr - stroking_data_selector(bool pixel_width_stroking); + stroking_data_selector(void); }; /*! @} */ diff --git a/src/fastuidraw/glsl/private/backend_shaders.cpp b/src/fastuidraw/glsl/private/backend_shaders.cpp index 916db6f7b..fd94b98b5 100644 --- a/src/fastuidraw/glsl/private/backend_shaders.cpp +++ b/src/fastuidraw/glsl/private/backend_shaders.cpp @@ -189,28 +189,23 @@ ShaderSetCreatorConstants(void) FASTUIDRAWassert(m_stroke_render_pass_num_bits + m_stroke_dash_style_num_bits + 1u <= 32u); m_stroke_render_pass_bit0 = 0; - m_stroke_width_pixels_bit0 = m_stroke_render_pass_bit0 + m_stroke_render_pass_num_bits; - m_stroke_dash_style_bit0 = m_stroke_width_pixels_bit0 + 1u; + m_stroke_dash_style_bit0 = m_stroke_render_pass_bit0 + m_stroke_render_pass_num_bits; } ShaderSource& ShaderSetCreatorConstants:: add_constants(ShaderSource &src, bool render_pass_varies) const { - unsigned int stroke_width_pixels_bit0(m_stroke_width_pixels_bit0); unsigned int stroke_dash_style_bit0(m_stroke_dash_style_bit0); unsigned int stroke_render_pass_num_bits(m_stroke_render_pass_num_bits); if (!render_pass_varies) { - stroke_width_pixels_bit0 -= m_stroke_render_pass_num_bits; stroke_dash_style_bit0 -= m_stroke_render_pass_num_bits; stroke_render_pass_num_bits -= m_stroke_render_pass_num_bits; } src - .add_macro("fastuidraw_stroke_sub_shader_width_pixels_bit0", stroke_width_pixels_bit0) - .add_macro("fastuidraw_stroke_sub_shader_width_pixels_num_bits", 1) .add_macro("fastuidraw_stroke_sub_shader_render_pass_bit0", m_stroke_render_pass_bit0) .add_macro("fastuidraw_stroke_sub_shader_render_pass_num_bits", stroke_render_pass_num_bits) .add_macro("fastuidraw_stroke_sub_shader_dash_style_bit0", stroke_dash_style_bit0) @@ -444,7 +439,6 @@ create_glyph_shader(bool anisotropic) reference_counted_ptr ShaderSetCreator:: create_stroke_item_shader(enum PainterEnums::cap_style stroke_dash_style, - bool pixel_width_stroking, enum uber_stroke_render_pass_t render_pass) { reference_counted_ptr shader; @@ -452,35 +446,29 @@ create_stroke_item_shader(enum PainterEnums::cap_style stroke_dash_style, if (stroke_dash_style == fastuidraw::PainterEnums::number_cap_styles) { - sub_shader = (render_pass << m_stroke_render_pass_bit0) - | (uint32_t(pixel_width_stroking) << m_stroke_width_pixels_bit0); + sub_shader = (render_pass << m_stroke_render_pass_bit0); shader = FASTUIDRAWnew PainterItemShader(sub_shader, m_uber_stroke_shader); } else { if (render_pass == uber_stroke_non_aa && m_dashed_discard_stroke_shader) { - sub_shader = (stroke_dash_style << (m_stroke_dash_style_bit0 - m_stroke_render_pass_num_bits)) - | (uint32_t(pixel_width_stroking) << (m_stroke_width_pixels_bit0 - m_stroke_render_pass_num_bits)); + sub_shader = (stroke_dash_style << (m_stroke_dash_style_bit0 - m_stroke_render_pass_num_bits)); shader = FASTUIDRAWnew PainterItemShader(sub_shader, m_dashed_discard_stroke_shader); } else { sub_shader = (stroke_dash_style << m_stroke_dash_style_bit0) - | (render_pass << m_stroke_render_pass_bit0) - | (uint32_t(pixel_width_stroking) << m_stroke_width_pixels_bit0); + | (render_pass << m_stroke_render_pass_bit0); shader = FASTUIDRAWnew PainterItemShader(sub_shader, m_uber_dashed_stroke_shader); } } return shader; } - - PainterStrokeShader ShaderSetCreator:: create_stroke_shader(enum PainterEnums::cap_style stroke_style, - bool pixel_width_stroking, const reference_counted_ptr &stroke_data_selector) { using namespace fastuidraw::PainterEnums; @@ -490,29 +478,29 @@ create_stroke_shader(enum PainterEnums::cap_style stroke_style, .aa_type(m_stroke_tp) .stroking_data_selector(stroke_data_selector) .aa_action_pass1(m_stroke_action_pass1) - .aa_shader_pass1(create_stroke_item_shader(stroke_style, pixel_width_stroking, uber_stroke_aa_pass1)) + .aa_shader_pass1(create_stroke_item_shader(stroke_style, uber_stroke_aa_pass1)) .aa_action_pass2(m_stroke_action_pass2) - .aa_shader_pass2(create_stroke_item_shader(stroke_style, pixel_width_stroking, uber_stroke_aa_pass2)) - .non_aa_shader(create_stroke_item_shader(stroke_style, pixel_width_stroking, uber_stroke_non_aa)); + .aa_shader_pass2(create_stroke_item_shader(stroke_style, uber_stroke_aa_pass2)) + .non_aa_shader(create_stroke_item_shader(stroke_style, uber_stroke_non_aa)); return return_value; } PainterDashedStrokeShaderSet ShaderSetCreator:: -create_dashed_stroke_shader_set(bool pixel_width_stroking) +create_dashed_stroke_shader_set(void) { using namespace fastuidraw::PainterEnums; PainterDashedStrokeShaderSet return_value; reference_counted_ptr de; reference_counted_ptr se; - se = PainterDashedStrokeParams::stroking_data_selector(pixel_width_stroking); - de = PainterDashedStrokeParams::dash_evaluator(pixel_width_stroking); + se = PainterDashedStrokeParams::stroking_data_selector(); + de = PainterDashedStrokeParams::dash_evaluator(); return_value .dash_evaluator(de) - .shader(flat_caps, create_stroke_shader(flat_caps, pixel_width_stroking, se)) - .shader(rounded_caps, create_stroke_shader(rounded_caps, pixel_width_stroking, se)) - .shader(square_caps, create_stroke_shader(square_caps, pixel_width_stroking, se)); + .shader(flat_caps, create_stroke_shader(flat_caps, se)) + .shader(rounded_caps, create_stroke_shader(rounded_caps, se)) + .shader(square_caps, create_stroke_shader(square_caps, se)); return return_value; } @@ -549,18 +537,15 @@ create_shader_set(void) { using namespace fastuidraw::PainterEnums; PainterShaderSet return_value; - reference_counted_ptr se, se_pixel; + reference_counted_ptr se; - se = PainterStrokeParams::stroking_data_selector(false); - se_pixel = PainterStrokeParams::stroking_data_selector(true); + se = PainterStrokeParams::stroking_data_selector(); return_value .glyph_shader(create_glyph_shader(false)) .glyph_shader_anisotropic(create_glyph_shader(true)) - .stroke_shader(create_stroke_shader(number_cap_styles, false, se)) - .pixel_width_stroke_shader(create_stroke_shader(number_cap_styles, true, se_pixel)) - .dashed_stroke_shader(create_dashed_stroke_shader_set(false)) - .pixel_width_dashed_stroke_shader(create_dashed_stroke_shader_set(true)) + .stroke_shader(create_stroke_shader(number_cap_styles, se)) + .dashed_stroke_shader(create_dashed_stroke_shader_set()) .fill_shader(create_fill_shader()) .blend_shaders(create_blend_shaders()); return return_value; diff --git a/src/fastuidraw/glsl/private/backend_shaders.hpp b/src/fastuidraw/glsl/private/backend_shaders.hpp index 956b2dd69..74c9189ed 100644 --- a/src/fastuidraw/glsl/private/backend_shaders.hpp +++ b/src/fastuidraw/glsl/private/backend_shaders.hpp @@ -75,7 +75,7 @@ class ShaderSetCreatorConstants remove_constants(ShaderSource &src) const; uint32_t m_stroke_render_pass_num_bits, m_stroke_dash_style_num_bits; - uint32_t m_stroke_width_pixels_bit0, m_stroke_render_pass_bit0, m_stroke_dash_style_bit0; + uint32_t m_stroke_render_pass_bit0, m_stroke_dash_style_bit0; }; class ShaderSetCreator: @@ -107,15 +107,13 @@ class ShaderSetCreator: */ PainterStrokeShader create_stroke_shader(enum PainterEnums::cap_style stroke_dash_style, - bool pixel_width_stroking, const reference_counted_ptr &stroke_data_selector); PainterDashedStrokeShaderSet - create_dashed_stroke_shader_set(bool pixel_width_stroking); + create_dashed_stroke_shader_set(void); reference_counted_ptr create_stroke_item_shader(enum PainterEnums::cap_style stroke_dash_style, - bool pixel_width_stroking, enum uber_stroke_render_pass_t render_pass_macro); PainterFillShader diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string index e95a0760d..f0328983e 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string @@ -364,7 +364,6 @@ fastuidraw_gl_vert_main(in uint sub_shader, primary_attrib = uintBitsToFloat(uprimary_attrib); secondary_attrib = uintBitsToFloat(usecondary_attrib); - uint width_pixels; uint render_pass; bool stroke_width_pixels; int stroking_pass; @@ -382,12 +381,6 @@ fastuidraw_gl_vert_main(in uint sub_shader, } #endif - width_pixels = FASTUIDRAW_EXTRACT_BITS(fastuidraw_stroke_sub_shader_width_pixels_bit0, - fastuidraw_stroke_sub_shader_width_pixels_num_bits, - sub_shader); - - - stroke_width_pixels = (width_pixels == uint(1)); stroking_pass = int(render_pass); vec2 p; @@ -422,7 +415,8 @@ fastuidraw_gl_vert_main(in uint sub_shader, 1, point_packed_data)); - stroke_radius = stroke_params.radius; + stroke_width_pixels = (stroke_params.radius < 0.0); + stroke_radius = abs(stroke_params.radius); #ifdef FASTUIDRAW_STROKE_DASHED { diff --git a/src/fastuidraw/painter/packing/painter_backend.cpp b/src/fastuidraw/painter/packing/painter_backend.cpp index 79f46c327..0f20d9507 100644 --- a/src/fastuidraw/painter/packing/painter_backend.cpp +++ b/src/fastuidraw/painter/packing/painter_backend.cpp @@ -258,9 +258,7 @@ fastuidraw::PainterBackend:: register_shader(const PainterShaderSet &shaders) { register_shader(shaders.stroke_shader()); - register_shader(shaders.pixel_width_stroke_shader()); register_shader(shaders.dashed_stroke_shader()); - register_shader(shaders.pixel_width_dashed_stroke_shader()); register_shader(shaders.fill_shader()); register_shader(shaders.glyph_shader()); register_shader(shaders.glyph_shader_anisotropic()); diff --git a/src/fastuidraw/painter/painter.cpp b/src/fastuidraw/painter/painter.cpp index bd7a0a22c..d9bb02299 100644 --- a/src/fastuidraw/painter/painter.cpp +++ b/src/fastuidraw/painter/painter.cpp @@ -1956,17 +1956,6 @@ stroke_path(const PainterData &draw, const Path &path, close_contours, cp, js, with_anti_aliasing, call_back); } -void -fastuidraw::Painter:: -stroke_path_pixel_width(const PainterData &draw, const Path &path, - bool close_contours, enum PainterEnums::cap_style cp, enum PainterEnums::join_style js, - bool with_anti_aliasing, - const reference_counted_ptr &call_back) -{ - stroke_path(default_shaders().pixel_width_stroke_shader(), draw, path, - close_contours, cp, js, with_anti_aliasing, call_back); -} - void fastuidraw::Painter:: stroke_dashed_path(const PainterDashedStrokeShaderSet &shader, const PainterData &draw, @@ -2012,17 +2001,6 @@ stroke_dashed_path(const PainterData &draw, const Path &path, close_contours, cp, js, with_anti_aliasing, call_back); } -void -fastuidraw::Painter:: -stroke_dashed_path_pixel_width(const PainterData &draw, const Path &path, - bool close_contours, enum PainterEnums::cap_style cp, enum PainterEnums::join_style js, - bool with_anti_aliasing, - const reference_counted_ptr &call_back) -{ - stroke_dashed_path(default_shaders().pixel_width_dashed_stroke_shader(), draw, path, - close_contours, cp, js, with_anti_aliasing, call_back); -} - void fastuidraw::Painter:: fill_path(const PainterFillShader &shader, const PainterData &draw, diff --git a/src/fastuidraw/painter/painter_dashed_stroke_params.cpp b/src/fastuidraw/painter/painter_dashed_stroke_params.cpp index af345c70f..315d7fbe7 100644 --- a/src/fastuidraw/painter/painter_dashed_stroke_params.cpp +++ b/src/fastuidraw/painter/painter_dashed_stroke_params.cpp @@ -46,6 +46,7 @@ namespace float m_miter_limit; float m_radius; + enum fastuidraw::PainterStrokeParams::stroking_units_t m_stroking_units; float m_dash_offset; float m_total_length; float m_first_interval_start; @@ -57,8 +58,7 @@ namespace { public: explicit - DashEvaluator(bool pixel_width_stroking): - m_pixel_width_stroking(pixel_width_stroking) + DashEvaluator(void) {} virtual @@ -70,8 +70,6 @@ namespace bool close_to_boundary(float dist, fastuidraw::range_type interval); - - bool m_pixel_width_stroking; }; } @@ -81,6 +79,7 @@ PainterDashedStrokeParamsData:: PainterDashedStrokeParamsData(void): m_miter_limit(15.0f), m_radius(1.0f), + m_stroking_units(fastuidraw::PainterStrokeParams::path_stroking_units), m_dash_offset(0.0f), m_total_length(0.0f), m_first_interval_start(0.0f) @@ -109,7 +108,14 @@ pack_data(unsigned int alignment, fastuidraw::c_array using namespace fastuidraw; dst[PainterDashedStrokeParams::stroke_miter_limit_offset].f = m_miter_limit; - dst[PainterDashedStrokeParams::stroke_radius_offset].f = m_radius; + if (m_stroking_units == PainterStrokeParams::pixel_stroking_units) + { + dst[PainterDashedStrokeParams::stroke_radius_offset].f = -m_radius; + } + else + { + dst[PainterDashedStrokeParams::stroke_radius_offset].f = m_radius; + } dst[PainterDashedStrokeParams::stroke_dash_offset_offset].f = m_dash_offset; dst[PainterDashedStrokeParams::stroke_total_length_offset].f = m_total_length; dst[PainterDashedStrokeParams::stroke_first_interval_start_offset].f = m_first_interval_start; @@ -235,7 +241,7 @@ width(float f) PainterDashedStrokeParamsData *d; FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); d = static_cast(m_data); - d->m_radius = 0.5f * f; + d->m_radius = (f > 0.0f) ? 0.5f * f : 0.0f; return *this; } @@ -256,7 +262,7 @@ radius(float f) PainterDashedStrokeParamsData *d; FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); d = static_cast(m_data); - d->m_radius = f; + d->m_radius = (f > 0.0f) ? f : 0.0f; return *this; } @@ -299,8 +305,7 @@ dash_pattern(c_array f) FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); d = static_cast(m_data); - /* skip to first element on f[] that is non-zero. - */ + /* skip to first element on f[] that is non-zero. */ while(f.front().m_draw_length <= 0.0f && f.front().m_space_length <= 0.0f) { f = f.sub_array(1); @@ -374,16 +379,37 @@ dash_pattern(c_array f) return *this; } +enum fastuidraw::PainterStrokeParams::stroking_units_t +fastuidraw::PainterDashedStrokeParams:: +stroking_units(void) const +{ + PainterDashedStrokeParamsData *d; + FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); + d = static_cast(m_data); + return d->m_stroking_units; +} + +fastuidraw::PainterDashedStrokeParams& +fastuidraw::PainterDashedStrokeParams:: +stroking_units(enum PainterStrokeParams::stroking_units_t v) +{ + PainterDashedStrokeParamsData *d; + FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); + d = static_cast(m_data); + d->m_stroking_units = v; + return *this; +} + fastuidraw::reference_counted_ptr fastuidraw::PainterDashedStrokeParams:: -dash_evaluator(bool pixel_width_stroking) +dash_evaluator(void) { - return FASTUIDRAWnew DashEvaluator(pixel_width_stroking); + return FASTUIDRAWnew DashEvaluator(); } fastuidraw::reference_counted_ptr fastuidraw::PainterDashedStrokeParams:: -stroking_data_selector(bool pixel_width_stroking) +stroking_data_selector(void) { - return PainterStrokeParams::stroking_data_selector(pixel_width_stroking); + return PainterStrokeParams::stroking_data_selector(); } diff --git a/src/fastuidraw/painter/painter_shader_set.cpp b/src/fastuidraw/painter/painter_shader_set.cpp index 8c183094c..bb87567ca 100644 --- a/src/fastuidraw/painter/painter_shader_set.cpp +++ b/src/fastuidraw/painter/painter_shader_set.cpp @@ -27,9 +27,7 @@ namespace public: fastuidraw::PainterGlyphShader m_glyph_shader, m_glyph_shader_anisotropic; fastuidraw::PainterStrokeShader m_stroke_shader; - fastuidraw::PainterStrokeShader m_pixel_width_stroke_shader; fastuidraw::PainterDashedStrokeShaderSet m_dashed_stroke_shader; - fastuidraw::PainterDashedStrokeShaderSet m_pixel_width_dashed_stroke_shader; fastuidraw::PainterFillShader m_fill_shader; fastuidraw::PainterBlendShaderSet m_blend_shaders; }; @@ -67,12 +65,8 @@ setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, const fastuidraw::PainterGlyphShader&, glyph_shader_anisotropic) setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, const fastuidraw::PainterStrokeShader&, stroke_shader) -setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, - const fastuidraw::PainterStrokeShader&, pixel_width_stroke_shader) setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, const fastuidraw::PainterDashedStrokeShaderSet&, dashed_stroke_shader) -setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, - const fastuidraw::PainterDashedStrokeShaderSet&, pixel_width_dashed_stroke_shader) setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, const fastuidraw::PainterFillShader&, fill_shader) setget_implement(fastuidraw::PainterShaderSet, PainterShaderSetPrivate, diff --git a/src/fastuidraw/painter/painter_stroke_params.cpp b/src/fastuidraw/painter/painter_stroke_params.cpp index 52279ceea..240af4c0a 100644 --- a/src/fastuidraw/painter/painter_stroke_params.cpp +++ b/src/fastuidraw/painter/painter_stroke_params.cpp @@ -28,7 +28,8 @@ namespace public: PainterStrokeParamsData(void): m_miter_limit(15.0f), - m_radius(1.0f) + m_radius(1.0f), + m_stroking_units(fastuidraw::PainterStrokeParams::path_stroking_units) {} virtual @@ -49,20 +50,30 @@ namespace void pack_data(unsigned int alignment, fastuidraw::c_array dst) const { + using namespace fastuidraw; FASTUIDRAWunused(alignment); - dst[fastuidraw::PainterStrokeParams::stroke_miter_limit_offset].f = m_miter_limit; - dst[fastuidraw::PainterStrokeParams::stroke_radius_offset].f = m_radius; + + dst[PainterStrokeParams::stroke_miter_limit_offset].f = m_miter_limit; + if (m_stroking_units == PainterStrokeParams::pixel_stroking_units) + { + dst[PainterStrokeParams::stroke_radius_offset].f = -m_radius; + } + else + { + dst[PainterStrokeParams::stroke_radius_offset].f = m_radius; + } } float m_miter_limit; float m_radius; + enum fastuidraw::PainterStrokeParams::stroking_units_t m_stroking_units; }; class StrokingDataSelector:public fastuidraw::StrokingDataSelectorBase { public: explicit - StrokingDataSelector(bool pixel_width); + StrokingDataSelector(void); virtual float @@ -73,9 +84,6 @@ namespace stroking_distances(const fastuidraw::PainterShaderData::DataBase *data, float *out_pixel_distance, float *out_item_space_distance) const; - - private: - bool m_pixel_width; }; } @@ -83,8 +91,7 @@ namespace //////////////////////////////// // StrokingDataSelector methods StrokingDataSelector:: -StrokingDataSelector(bool pixel_width): - m_pixel_width(pixel_width) +StrokingDataSelector(void) {} float @@ -108,7 +115,7 @@ compute_thresh(const fastuidraw::PainterShaderData::DataBase *data, float return_value; return_value = curve_flatness / d->m_radius; - if (!m_pixel_width) + if (d->m_stroking_units == fastuidraw::PainterStrokeParams::path_stroking_units) { return_value /= path_magnification; } @@ -125,15 +132,15 @@ stroking_distances(const fastuidraw::PainterShaderData::DataBase *data, const PainterStrokeParamsData *d; d = static_cast(data); - if (m_pixel_width) + if (d->m_stroking_units == fastuidraw::PainterStrokeParams::path_stroking_units) { - *out_pixel_distance = d->m_radius; - *out_item_space_distance = 0.0f; + *out_pixel_distance = 0.0f; + *out_item_space_distance = d->m_radius; } else { - *out_pixel_distance = 0.0f; - *out_item_space_distance = d->m_radius; + *out_pixel_distance = d->m_radius; + *out_item_space_distance = 0.0f; } } @@ -183,7 +190,7 @@ width(float f) PainterStrokeParamsData *d; FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); d = static_cast(m_data); - d->m_radius = 0.5f * f; + d->m_radius = (f > 0.0f ) ? 0.5f * f : 0.0f; return *this; } @@ -204,13 +211,34 @@ radius(float f) PainterStrokeParamsData *d; FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); d = static_cast(m_data); - d->m_radius = f; + d->m_radius = (f > 0.0f ) ? f : 0.0f; + return *this; +} + +enum fastuidraw::PainterStrokeParams::stroking_units_t +fastuidraw::PainterStrokeParams:: +stroking_units(void) const +{ + PainterStrokeParamsData *d; + FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); + d = static_cast(m_data); + return d->m_stroking_units; +} + +fastuidraw::PainterStrokeParams& +fastuidraw::PainterStrokeParams:: +stroking_units(enum stroking_units_t v) +{ + PainterStrokeParamsData *d; + FASTUIDRAWassert(dynamic_cast(m_data) != nullptr); + d = static_cast(m_data); + d->m_stroking_units = v; return *this; } fastuidraw::reference_counted_ptr fastuidraw::PainterStrokeParams:: -stroking_data_selector(bool pixel_width_stroking) +stroking_data_selector(void) { - return FASTUIDRAWnew StrokingDataSelector(pixel_width_stroking); + return FASTUIDRAWnew StrokingDataSelector(); } From 4060749878826db2d31588b84911a4772adad425 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Fri, 27 Apr 2018 15:35:45 +0300 Subject: [PATCH 11/52] fastuidraw/painter/stroked_caps_joins: initial commit of StrokedCapsJoins implementation The purpose of StrokeCapsJoins is to decouple the drawing of caps/joins from the rest of stroking to make way for possible other ways to stroke (that use far fewer vertices). --- inc/fastuidraw/painter/stroked_caps_joins.hpp | 333 ++ inc/fastuidraw/tessellated_path.hpp | 1 + src/fastuidraw/painter/Rules.mk | 3 +- src/fastuidraw/painter/stroked_caps_joins.cpp | 3149 +++++++++++++++++ src/fastuidraw/tessellated_path.cpp | 3 +- 5 files changed, 3487 insertions(+), 2 deletions(-) create mode 100644 inc/fastuidraw/painter/stroked_caps_joins.hpp create mode 100644 src/fastuidraw/painter/stroked_caps_joins.cpp diff --git a/inc/fastuidraw/painter/stroked_caps_joins.hpp b/inc/fastuidraw/painter/stroked_caps_joins.hpp new file mode 100644 index 000000000..d66cddd57 --- /dev/null +++ b/inc/fastuidraw/painter/stroked_caps_joins.hpp @@ -0,0 +1,333 @@ +/*! + * \file stroked_caps_joins.hpp + * \brief file stroked_caps_joins.hpp + * + * Copyright 2018 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace fastuidraw { + +///@cond +class PainterAttributeData; +class DashEvaluatorBase; +///@endcond + +/*!\addtogroup Paths + * @{ + */ + +/*! + * \brief + * A StrokedCapsJoins represents the data needed to draw a the joins + * and caps of a stroked path. It contains -all- the data needed to + * do regardless of stroking parameters. + * + * The data is stored as \ref PainterAttributeData, a seperate + * object for each type of join and each type of cap. What chunks + * to use from these objects is computed by the member function + * compute_chunks(); the PainterAttributeData chunking for joins + * and caps is the same regardless of the cap and join type. + */ +class StrokedCapsJoins: + public reference_counted::non_concurrent +{ +public: + /*! + * \brief + * Opaque object to hold work room needed for functions + * of StrokedPath that require scratch space. + */ + class ScratchSpace:fastuidraw::noncopyable + { + public: + ScratchSpace(void); + ~ScratchSpace(); + private: + friend class StrokedCapsJoins; + void *m_d; + }; + + /*! + * \brief + * Object to hold the output of a chunk query via compute_chunks(). + */ + class ChunkSet:fastuidraw::noncopyable + { + public: + ChunkSet(void); + + ~ChunkSet(); + + /*! + * The list of chunks to take from any of StrokedCapsJoins::bevel_joins(), + * StrokedCapsJoins::miter_clip_joins(), StrokedCapsJoins::miter_bevel_joins(), + * StrokedCapsJoins::miter_joins() or StrokedCapsJoins::rounded_joins() that + * have visible content. + */ + c_array + join_chunks(void) const; + + /*! + * The list of chunks to take from any of StrokedCapsJoins::square_caps(), + * StrokedCapsJoins::adjustable_caps() or StrokedCapsJoins::rounded_caps() + * that have visible content. + */ + c_array + cap_chunks(void) const; + + private: + friend class StrokedCapsJoins; + void *m_d; + }; + + /*! + * Enumeration to select the chunk of all joins + * of the closing edges or non-closing edges + */ + enum chunk_selection + { + /*! + * Select the chunk that holds all the joins + * of ONLY the non-closing edges + */ + all_non_closing, + + /*! + * Select the chunk that holds all the joins + * of ONLY the closing edges + */ + all_closing, + }; + + /*! + * \brief + * A Builder is used to specify the nature of the contours + * from which to geneate joins and caps. + */ + class Builder:fastuidraw::noncopyable + { + public: + Builder(void); + ~Builder(); + + /*! + * Begin a contour + * \param start_pt starting point of contour + * \param start_direction unit vector from start point to next point + */ + void + begin_contour(const vec2 &start_pt, + const vec2 &start_direction); + + + /*! + * Add a join + * \param join_pt location of join + * \param distance_from_previous_join distance from previous join + * \param direction_into_join unit vector of path into the join + * \param direction_leaving_join unit vector of path leaving the join + */ + void + add_join(const vec2 &join_pt, + float distance_from_previous_join, + const vec2 &direction_into_join, + const vec2 &direction_leaving_join); + + /*! + * End the contour. + * \param distance_from_previous_join distance from previous join + * \param direction_into_join unit vector of path into the join that + * links the closing edge to the 1st point + */ + void + end_contour(float distance_from_previous_join, + const vec2 &direction_into_join); + + private: + friend class StrokedCapsJoins; + void *m_d; + }; + + /*! + * Ctor. + * \param b Builder holding the data to generate joins and caps + */ + explicit + StrokedCapsJoins(const Builder &b); + + ~StrokedCapsJoins(); + + /*! + * Given a set of clip equations in clip coordinates + * and a tranformation from local coordiante to clip + * coordinates, compute what chunks are not completely + * culled by the clip equations. + * \param scratch_space scratch space for computations + * \param dash_evaluator if doing dashed stroking, the dash evalulator will cull + * joins not to be drawn, if nullptr only those joins not in the + * visible area defined by clip_equations are culled. + * \param dash_data data to pass to dast evaluator + * \param clip_equations array of clip equations + * \param clip_matrix_local 3x3 transformation from local (x, y, 1) + * coordinates to clip coordinates. + * \param recip_dimensions holds the reciprocal of the dimensions of the viewport + * \param pixels_additional_room amount in -pixels- to push clip equations by + * to grab additional edges + * \param item_space_additional_room amount in local coordinates to push clip + * equations by to grab additional edges + * draw the closing edges of each contour + * \param include_closing_edges if true include the chunks needed to + * \param max_attribute_cnt only allow those chunks for which have no more + * than max_attribute_cnt attributes + * \param max_index_cnt only allow those chunks for which have no more + * than max_index_cnt indices + * \param take_joins_outside_of_region if true, take even those joins outside of the region + * (this is for handling miter-joins where the weather + * or not a miter-join is included is also a function of + * the miter-limit when stroking). + * \param[out] dst location to which to write output + */ + void + compute_chunks(ScratchSpace &scratch_space, + const DashEvaluatorBase *dash_evaluator, + const PainterShaderData::DataBase *dash_data, + c_array clip_equations, + const float3x3 &clip_matrix_local, + const vec2 &recip_dimensions, + float pixels_additional_room, + float item_space_additional_room, + bool include_closing_edges, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + bool take_joins_outside_of_region, + ChunkSet &dst) const; + + /*! + * Returns the number of joins of the StrokedPath + * \param include_joins_of_closing_edge if false disclude from the count, + * this joins of the closing edges + */ + unsigned int + number_joins(bool include_joins_of_closing_edge) const; + + /*! + * Returns a chunk value for Painter::attribute_data_chunk() + * and related calls to feed the return value to any of + * bevel_joins(), miter_clip_joins(), miter_bevel_joins(), + * miter_joins() or rounded_joins() to fetch the chunk + * of the named join. + * \param J join ID with 0 <= J < number_joins(true) + */ + unsigned int + join_chunk(unsigned int J) const; + + /*! + * Return the chunk to feed to any of bevel_joins(), + * miter_clip_joins(), miter_bevel_joins(), + * miter_joins() or rounded_joins() that holds all + * the joins of the closing edges or all the joins + * of the non-closing edges. + * \param c select joins of closing or non-closing edges + */ + unsigned int + chunk_of_joins(enum chunk_selection c) const; + + /*! + * Return the chunk to feed any of square_caps(), + * adjustable_caps() or rounded_caps() that holds + * data for all caps of this StrokedPath. + */ + unsigned int + chunk_of_caps(void) const; + + /*! + * Returns the data to draw the square caps of a stroked path. + */ + const PainterAttributeData& + square_caps(void) const; + + /*! + * Returns the data to draw the caps of a stroked path used + * when stroking with a dash pattern. + */ + const PainterAttributeData& + adjustable_caps(void) const; + + /*! + * Returns the data to draw the bevel joins of a stroked path. + */ + const PainterAttributeData& + bevel_joins(void) const; + + /*! + * Returns the data to draw the miter joins of a stroked path, + * if the miter-limit is exceeded on stroking, the miter-join + * is clipped to the miter-limit. + */ + const PainterAttributeData& + miter_clip_joins(void) const; + + /*! + * Returns the data to draw the miter joins of a stroked path, + * if the miter-limit is exceeded on stroking, the miter-join + * is to be drawn as a bevel join. + */ + const PainterAttributeData& + miter_bevel_joins(void) const; + + /*! + * Returns the data to draw the miter joins of a stroked path, + * if the miter-limit is exceeded on stroking, the miter-join + * end point is clamped to the miter-distance. + */ + const PainterAttributeData& + miter_joins(void) const; + + /*! + * Returns the data to draw rounded joins of a stroked path. + * \param thresh will return rounded joins so that the distance + * between the approximation of the round and the + * actual round is no more than thresh. + */ + const PainterAttributeData& + rounded_joins(float thresh) const; + + /*! + * Returns the data to draw rounded caps of a stroked path. + * \param thresh will return rounded caps so that the distance + * between the approximation of the round and the + * actual round is no more than thresh. + */ + const PainterAttributeData& + rounded_caps(float thresh) const; + +private: + void *m_d; +}; + +/*! @} */ + + +} diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index 8578097b0..ed41f1938 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace fastuidraw { diff --git a/src/fastuidraw/painter/Rules.mk b/src/fastuidraw/painter/Rules.mk index 5769b363f..846daefe9 100644 --- a/src/fastuidraw/painter/Rules.mk +++ b/src/fastuidraw/painter/Rules.mk @@ -20,7 +20,8 @@ FASTUIDRAW_SOURCES += $(call filelist, fill_rule.cpp \ painter_shader.cpp painter_shader_set.cpp \ painter_dashed_stroke_shader_set.cpp painter_stroke_shader.cpp \ painter_glyph_shader.cpp painter_blend_shader_set.cpp \ - painter_fill_shader.cpp stroked_point.cpp \ + painter_fill_shader.cpp \ + stroked_caps_joins.cpp stroked_point.cpp \ stroked_path.cpp filled_path.cpp) # Begin standard footer diff --git a/src/fastuidraw/painter/stroked_caps_joins.cpp b/src/fastuidraw/painter/stroked_caps_joins.cpp new file mode 100644 index 000000000..01fb60fd6 --- /dev/null +++ b/src/fastuidraw/painter/stroked_caps_joins.cpp @@ -0,0 +1,3149 @@ +/*! + * \file stroked_caps_joins.cpp + * \brief file stroked_caps_joins.cpp + * + * Copyright 2018 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../private/util_private.hpp" +#include "../private/util_private_ostream.hpp" +#include "../private/bounding_box.hpp" +#include "../private/path_util_private.hpp" +#include "../private/clip.hpp" + + +namespace +{ + inline + uint32_t + pack_data(int on_boundary, + enum fastuidraw::StrokedPoint::offset_type_t pt, + uint32_t depth) + { + using namespace fastuidraw; + FASTUIDRAWassert(on_boundary == 0 || on_boundary == 1); + + uint32_t bb(on_boundary), pp(pt); + return pack_bits(StrokedPoint::offset_type_bit0, + StrokedPoint::offset_type_num_bits, pp) + | pack_bits(StrokedPoint::boundary_bit, 1u, bb) + | pack_bits(StrokedPoint::depth_bit0, + StrokedPoint::depth_num_bits, depth); + } + + inline + uint32_t + pack_data_join(int on_boundary, + enum fastuidraw::StrokedPoint::offset_type_t pt, + uint32_t depth) + { + return pack_data(on_boundary, pt, depth) | fastuidraw::StrokedPoint::join_mask; + } + + void + add_triangle_fan(unsigned int begin, unsigned int end, + fastuidraw::c_array indices, + unsigned int &index_offset) + { + for(unsigned int i = begin + 1; i < end - 1; ++i, index_offset += 3) + { + indices[index_offset + 0] = begin; + indices[index_offset + 1] = i; + indices[index_offset + 2] = i + 1; + } + } + + class PerJoinData + { + public: + PerJoinData(const fastuidraw::vec2 &p, + float distance_from_previous_join, + const fastuidraw::vec2 &tangent_into_join, + const fastuidraw::vec2 &tangent_leaving_join); + + const fastuidraw::vec2& + n0(void) const + { + return m_normal_into_join; + } + + const fastuidraw::vec2& + n1(void) const + { + return m_normal_leaving_join; + } + + void + set_distance_values(fastuidraw::StrokedPoint *pt) const + { + pt->m_distance_from_edge_start = m_distance_from_previous_join; + pt->m_edge_length = m_distance_from_previous_join; + pt->m_open_contour_length = m_open_contour_length; + pt->m_closed_contour_length = m_closed_contour_length; + pt->m_distance_from_contour_start = m_distance_from_contour_start; + } + + /* given values from creation */ + bool m_of_closing_edge; + fastuidraw::vec2 m_p; + fastuidraw::vec2 m_tangent_into_join, m_tangent_leaving_join; + float m_distance_from_previous_join; + float m_distance_from_contour_start; + float m_open_contour_length; + float m_closed_contour_length; + + /* derived values from creation */ + fastuidraw::vec2 m_normal_into_join, m_normal_leaving_join; + float m_det, m_lambda; + }; + + class PerCapData + { + public: + fastuidraw::vec2 m_tangent_into_cap; + fastuidraw::vec2 m_p; + float m_distance_from_edge_start; + float m_distance_from_contour_start; + float m_open_contour_length; + float m_closed_contour_length; + bool m_is_starting_cap; + + void + set_distance_values(fastuidraw::StrokedPoint *pt) const + { + pt->m_distance_from_edge_start = m_distance_from_edge_start; + pt->m_edge_length = m_distance_from_edge_start; + pt->m_open_contour_length = m_open_contour_length; + pt->m_closed_contour_length = m_closed_contour_length; + pt->m_distance_from_contour_start = m_distance_from_contour_start; + } + }; + + class PerContourData + { + public: + PerContourData(void): + m_cap_count(0) + {} + + void + start(const fastuidraw::vec2 &p, + const fastuidraw::vec2 &tangent_along_curve) + { + FASTUIDRAWassert(m_cap_count == 0); + m_caps[0].m_p = p; + m_caps[0].m_tangent_into_cap = -tangent_along_curve; + m_caps[0].m_distance_from_edge_start = 0.0f; + m_caps[0].m_distance_from_contour_start = 0.0f; + m_caps[0].m_is_starting_cap = true; + m_cap_count = 1; + } + + void + end(float distance_from_previous_join, + const fastuidraw::vec2 &direction_into_join) + { + fastuidraw::vec2 end_cap_pt, end_cap_direction; + float end_cap_edge_distance; + + /* the last added join starts the closing edge */ + if (!m_joins.empty()) + { + end_cap_pt = m_joins.back().m_p; + end_cap_direction = m_joins.back().m_tangent_into_join; + end_cap_edge_distance = m_joins.back().m_distance_from_previous_join; + m_joins.back().m_of_closing_edge = true; + + /* add the join ending the closing edge */ + add_join(m_caps[0].m_p, distance_from_previous_join, + direction_into_join, + -m_caps[0].m_tangent_into_cap); + m_joins.back().m_of_closing_edge = true; + } + else + { + end_cap_edge_distance = 0; + end_cap_pt = m_caps[0].m_p; + end_cap_direction = m_caps[0].m_tangent_into_cap; + } + + /* compute the contour lengths */ + float d(0.0f); + for(unsigned int i = 0, endi = m_joins.size(); i < endi; ++i) + { + d += m_joins[i].m_distance_from_previous_join; + m_joins[i].m_distance_from_contour_start = d; + } + + for (PerJoinData &J : m_joins) + { + J.m_closed_contour_length = d; + J.m_open_contour_length = d - distance_from_previous_join; + } + + for (PerCapData &C : m_caps) + { + C.m_closed_contour_length = m_joins.empty() ? 0.0f : d; + C.m_open_contour_length = m_joins.empty() ? distance_from_previous_join : d - distance_from_previous_join; + } + + m_caps[1].m_p = end_cap_pt; + m_caps[1].m_tangent_into_cap = end_cap_direction; + m_caps[1].m_distance_from_edge_start = end_cap_edge_distance; + m_caps[1].m_distance_from_contour_start = m_caps[1].m_open_contour_length; + m_caps[1].m_is_starting_cap = false; + + m_cap_count = 2; + } + + void + add_join(const fastuidraw::vec2 &p, + float distance_from_previous_join, + const fastuidraw::vec2 &tangent_into_join, + const fastuidraw::vec2 &tangent_leaving_join) + { + FASTUIDRAWassert(m_cap_count == 1); + m_joins.push_back(PerJoinData(p, distance_from_previous_join, + tangent_into_join, tangent_leaving_join)); + } + + const PerCapData& + cap(unsigned int I) const + { + FASTUIDRAWassert(m_cap_count == 2); + return m_caps[I]; + } + + fastuidraw::c_array + joins_of_non_closing_edges(void) const + { + fastuidraw::c_array r; + if (m_joins.size() > 2) + { + r = fastuidraw::make_c_array(m_joins); + r = r.sub_array(0, m_joins.size() - 2); + } + return r; + } + + fastuidraw::c_array + joins_of_closing_edges(void) const + { + fastuidraw::c_array r; + + r = fastuidraw::make_c_array(m_joins); + if (m_joins.size() > 2) + { + r = r.sub_array(m_joins.size() - 2); + } + return r; + } + + private: + std::vector m_joins; + fastuidraw::vecN m_caps; + unsigned int m_cap_count; + }; + + class ContourData:fastuidraw::noncopyable + { + public: + fastuidraw::BoundingBox m_bounding_box; + std::vector m_per_contour_data; + }; + + template + class OrderingEntry:public T + { + public: + OrderingEntry(const T &src, unsigned int chunk): + T(src), + m_chunk(chunk), + m_depth(0) + {} + + unsigned int m_chunk; + unsigned int m_depth; + }; + + /* provides in what chunk each Join is located. */ + class JoinOrdering + { + public: + fastuidraw::c_array > + non_closing_edge(void) const + { + return fastuidraw::make_c_array(m_non_closing_edge); + } + + fastuidraw::c_array > + closing_edge(void) const + { + return fastuidraw::make_c_array(m_closing_edge); + } + + void + add_join(const PerJoinData &src, unsigned int &chunk) + { + OrderingEntry J(src, chunk); + if (src.m_of_closing_edge) + { + m_closing_edge.push_back(J); + } + else + { + m_non_closing_edge.push_back(J); + } + ++chunk; + } + + void + post_process_non_closing(fastuidraw::range_type join_range, + unsigned int &depth) + { + unsigned int R, d; + + /* the depth values of the joins must come in reverse + * so that higher depth values occlude later elements + */ + R = join_range.difference(); + d = depth + R - 1; + + for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_non_closing_edge.size()); + m_non_closing_edge[i].m_depth = d; + } + depth += R; + } + + void + post_process_closing(unsigned int non_closing_edge_chunk_count, + fastuidraw::range_type join_range, + unsigned int &depth) + { + unsigned int R, d; + + /* the depth values of the joins must come in reverse + * so that higher depth values occlude later elements + */ + R = join_range.difference(); + d = depth + R - 1; + + for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_closing_edge.size()); + m_closing_edge[i].m_depth = d; + m_closing_edge[i].m_chunk += non_closing_edge_chunk_count; + } + depth += R; + } + + unsigned int + number_joins(bool include_joins_of_closing_edge) const + { + return include_joins_of_closing_edge ? + m_non_closing_edge.size() + m_closing_edge.size() : + m_non_closing_edge.size(); + } + + unsigned int + join_chunk(unsigned int J) const + { + FASTUIDRAWassert(J < number_joins(true)); + if (J >= m_non_closing_edge.size()) + { + J -= m_non_closing_edge.size(); + return m_closing_edge[J].m_chunk; + } + else + { + return m_non_closing_edge[J].m_chunk; + } + } + + private: + std::vector > m_non_closing_edge; + std::vector > m_closing_edge; + }; + + class CapOrdering + { + public: + fastuidraw::c_array > + caps(void) const + { + return fastuidraw::make_c_array(m_caps); + } + + void + add_cap(const PerCapData &src, unsigned int &chunk) + { + OrderingEntry C(src, chunk); + m_caps.push_back(C); + ++chunk; + } + + void + post_process(fastuidraw::range_type range, + unsigned int &depth) + { + unsigned int R, d; + + /* the depth values of the caps must come in reverse + * so that higher depth values occlude later elements + */ + R = range.difference(); + d = depth + R - 1; + for(unsigned int i = range.m_begin; i < range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_caps.size()); + m_caps[i].m_depth = d; + } + depth += R; + } + + private: + std::vector > m_caps; + }; + + class PathData:fastuidraw::noncopyable + { + public: + fastuidraw::BoundingBox m_bounding_box; + + JoinOrdering m_join_ordering; + unsigned int m_number_join_chunks; + CapOrdering m_cap_ordering; + unsigned int m_number_cap_chunks; + }; + + /* A CullingHierarchy represents a hierarchy choice of + * what joins and caps in each element of a hierarchy. + */ + class CullingHierarchy:fastuidraw::noncopyable + { + public: + static + CullingHierarchy* + create(const ContourData &contour_data); + + ~CullingHierarchy(); + + bool + has_children(void) const + { + bool b0(m_children[0] != nullptr); + bool b1(m_children[1] != nullptr); + + FASTUIDRAWassert(b0 == b1); + FASTUIDRAWunused(b0); + FASTUIDRAWunused(b1); + return m_children[0] != nullptr; + } + + const CullingHierarchy* + child(unsigned int i) const + { + return m_children[i]; + } + + fastuidraw::c_array + non_closing_joins(void) const + { + return m_joins_non_closing_edge; + } + + fastuidraw::c_array + closing_joins(void) const + { + return m_joins_closing_edge; + } + + fastuidraw::c_array + caps(void) const + { + return fastuidraw::make_c_array(m_caps); + } + + const fastuidraw::BoundingBox& + bounding_box(void) const + { + return m_bb; + } + + private: + enum + { + splitting_threshhold = 10 + }; + + CullingHierarchy(const fastuidraw::BoundingBox &bb, + std::vector &joins, std::vector &caps); + + /* a value of -1 means to NOT split. + */ + static + int + choose_splitting_coordinate(const fastuidraw::BoundingBox &start_box, + fastuidraw::c_array joins, + fastuidraw::c_array caps, + float &split_value); + + /* children, if any */ + fastuidraw::vecN m_children; + + /* Caps inside, only non-empty if has no children. */ + std::vector m_caps; + + /* Joins inside, only non-empty if has no children. */ + std::vector m_joins; + fastuidraw::c_array m_joins_non_closing_edge; + fastuidraw::c_array m_joins_closing_edge; + + /* bounding box of this + */ + fastuidraw::BoundingBox m_bb; + }; + + class ScratchSpacePrivate:fastuidraw::noncopyable + { + public: + std::vector m_adjusted_clip_eqs; + std::vector m_clipped_rect; + + fastuidraw::vecN, 2> m_clip_scratch_vec2s; + std::vector m_clip_scratch_floats; + }; + + class RangeAndChunk + { + public: + /* what range of Joins/Caps hit by the chunk. + */ + fastuidraw::range_type m_elements; + + /* depth range of Joins/Caps hit + */ + fastuidraw::range_type m_depth_range; + + /* what the chunk is + */ + unsigned int m_chunk; + + bool + non_empty(void) const + { + return m_depth_range.m_end > m_depth_range.m_begin; + } + }; + + class ChunkSetPrivate:fastuidraw::noncopyable + { + public: + void + reset(void) + { + m_ignore_join_adds = false; + m_join_chunks.clear(); + m_join_ranges.clear(); + m_cap_chunks.clear(); + } + + void + add_join_chunk(const RangeAndChunk &j); + + void + add_cap_chunk(const RangeAndChunk &c); + + fastuidraw::c_array + join_chunks(void) const + { + return fastuidraw::make_c_array(m_join_chunks); + } + + fastuidraw::c_array + cap_chunks(void) const + { + return fastuidraw::make_c_array(m_cap_chunks); + } + + void + ignore_join_adds(void) + { + m_ignore_join_adds = true; + } + + void + handle_dashed_evaluator(const fastuidraw::DashEvaluatorBase *dash_evaluator, + const fastuidraw::PainterShaderData::DataBase *dash_data, + const fastuidraw::StrokedCapsJoins &path); + + private: + std::vector m_join_chunks, m_cap_chunks; + std::vector > m_join_ranges; + bool m_ignore_join_adds; + }; + + /* Subset of a StrokedCapsJoins. Edges are to be placed into + * the store as follows: + * 1. child0 + * 2. child1 + * 3. caps/joins (i.e. from CullingHierarchy) + */ + class SubsetPrivate + { + public: + + class CreationValues + { + public: + CreationValues(void): + m_non_closing_join_chunk_cnt(0), + m_closing_join_chunk_cnt(0), + m_cap_chunk_cnt(0) + {} + + unsigned int m_non_closing_join_chunk_cnt; + unsigned int m_closing_join_chunk_cnt; + + unsigned int m_cap_chunk_cnt; + }; + + static + SubsetPrivate* + create(const CullingHierarchy *src, + CreationValues &out_values, + JoinOrdering &join_ordering, + CapOrdering &cap_ordering); + + ~SubsetPrivate(); + + void + compute_chunks(bool include_closing_edge, + ScratchSpacePrivate &work_room, + fastuidraw::c_array clip_equations, + const fastuidraw::float3x3 &clip_matrix_local, + const fastuidraw::vec2 &recip_dimensions, + float pixels_additional_room, + float item_space_additional_room, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + bool take_joins_outside_of_region, + ChunkSetPrivate &dst); + + bool + have_children(void) const + { + bool b0(m_children[0] != nullptr); + bool b1(m_children[1] != nullptr); + + FASTUIDRAWassert(b0 == b1); + FASTUIDRAWunused(b0); + FASTUIDRAWunused(b1); + return m_children[0] != nullptr; + } + + const SubsetPrivate* + child(unsigned int I) const + { + FASTUIDRAWassert(have_children()); + FASTUIDRAWassert(I == 0 || I == 1); + return m_children[I]; + } + + const RangeAndChunk& + non_closing_joins(void) const + { + return m_non_closing_joins; + } + + const RangeAndChunk& + closing_joins(void) const + { + return m_closing_joins; + } + + const RangeAndChunk& + caps(void) const + { + return m_caps; + } + + private: + class PostProcessVariables + { + public: + PostProcessVariables(void): + m_join_depth(0), + m_closing_join_depth(0), + m_cap_depth(0) + {} + + unsigned int m_join_depth, m_closing_join_depth; + unsigned int m_cap_depth; + }; + + SubsetPrivate(CreationValues &out_values, + JoinOrdering &join_ordering, + CapOrdering &cap_ordering, + const CullingHierarchy *src); + + void + compute_chunks_implement(bool include_closing_edge, + ScratchSpacePrivate &work_room, + float item_space_additional_room, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + ChunkSetPrivate &dst); + + void + compute_chunks_take_all(bool include_closing_edge, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + ChunkSetPrivate &dst); + void + post_process(PostProcessVariables &variables, + const CreationValues &constants, + JoinOrdering &join_ordering, + CapOrdering &cap_ordering); + + fastuidraw::vecN m_children; + + /* book keeping for joins */ + RangeAndChunk m_non_closing_joins, m_closing_joins; + + /* book keeping for caps */ + RangeAndChunk m_caps; + + fastuidraw::BoundingBox m_bb; + + bool m_empty_subset; + }; + + class JoinCount + { + public: + explicit + JoinCount(const JoinOrdering &J): + m_number_close_joins(J.closing_edge().size()), + m_number_non_close_joins(J.non_closing_edge().size()) + {} + + unsigned int m_number_close_joins; + unsigned int m_number_non_close_joins; + }; + + class JoinCreatorBase:public fastuidraw::PainterAttributeDataFiller + { + public: + explicit + JoinCreatorBase(const PathData &P, const SubsetPrivate *st); + + virtual + ~JoinCreatorBase() {} + + virtual + void + compute_sizes(unsigned int &num_attributes, + unsigned int &num_indices, + unsigned int &num_attribute_chunks, + unsigned int &num_index_chunks, + unsigned int &number_z_ranges) const; + + virtual + void + fill_data(fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) const; + + protected: + + void + post_ctor_initalize(void); + + private: + + void + fill_join(unsigned int join_id, const PerJoinData &join_data, + unsigned int chunk, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges) const; + + static + void + set_chunks(const SubsetPrivate *st, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts); + + static + void + process_chunk(const RangeAndChunk &ch, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts); + + virtual + void + add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const = 0; + + virtual + void + fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const = 0; + + const JoinOrdering &m_ordering; + const SubsetPrivate *m_st; + unsigned int m_num_verts, m_num_indices, m_num_chunks, m_num_joins; + bool m_post_ctor_initalized_called; + }; + + + class RoundedJoinCreator:public JoinCreatorBase + { + public: + RoundedJoinCreator(const PathData &P, + const SubsetPrivate *st, + float thresh); + + private: + + class PerRoundedJoin:public PerJoinData + { + public: + PerRoundedJoin(const PerJoinData &J, float thresh); + + void + add_data(unsigned int depth, + fastuidraw::c_array pts, + unsigned int &vertex_offset, + fastuidraw::c_array indices, + unsigned int &index_offset) const; + + std::complex m_arc_start; + float m_delta_theta; + unsigned int m_num_arc_points; + }; + + virtual + void + add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const; + + virtual + void + fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const; + + float m_thresh; + mutable std::vector m_per_join_data; + }; + + class BevelJoinCreator:public JoinCreatorBase + { + public: + explicit + BevelJoinCreator(const PathData &P, const SubsetPrivate *st); + + private: + + virtual + void + add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const; + + virtual + void + fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const; + }; + + class MiterClipJoinCreator:public JoinCreatorBase + { + public: + explicit + MiterClipJoinCreator(const PathData &P, const SubsetPrivate *st); + + private: + virtual + void + add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const; + + virtual + void + fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const; + }; + + template + class MiterJoinCreator:public JoinCreatorBase + { + public: + explicit + MiterJoinCreator(const PathData &P, const SubsetPrivate *st); + + private: + virtual + void + add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const; + + virtual + void + fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const; + }; + + class PointIndexCapSize + { + public: + PointIndexCapSize(void): + m_verts(0), + m_indices(0) + {} + + unsigned int m_verts, m_indices; + }; + + class CapCreatorBase:public fastuidraw::PainterAttributeDataFiller + { + public: + CapCreatorBase(const PathData &P, + const SubsetPrivate *st, + PointIndexCapSize sz); + + virtual + ~CapCreatorBase() + {} + + virtual + void + compute_sizes(unsigned int &num_attributes, + unsigned int &num_indices, + unsigned int &num_attribute_chunks, + unsigned int &num_index_chunks, + unsigned int &number_z_ranges) const; + + virtual + void + fill_data(fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) const; + + private: + virtual + void + add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const = 0; + + static + void + set_chunks(const SubsetPrivate *st, + fastuidraw::c_array > cap_vertex_ranges, + fastuidraw::c_array > cap_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts); + + const CapOrdering &m_ordering; + const SubsetPrivate *m_st; + + unsigned int m_num_chunks; + PointIndexCapSize m_size; + }; + + class RoundedCapCreator:public CapCreatorBase + { + public: + RoundedCapCreator(const PathData &P, + const SubsetPrivate *st, + float thresh); + + private: + static + PointIndexCapSize + compute_size(const PathData &P, float thresh); + + virtual + void + add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const; + + float m_delta_theta; + unsigned int m_num_arc_points_per_cap; + }; + + class SquareCapCreator:public CapCreatorBase + { + public: + explicit + SquareCapCreator(const PathData &P, + const SubsetPrivate *st): + CapCreatorBase(P, st, compute_size(P)) + {} + + private: + static + PointIndexCapSize + compute_size(const PathData &P); + + void + add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const; + }; + + class AdjustableCapCreator:public CapCreatorBase + { + public: + AdjustableCapCreator(const PathData &P, + const SubsetPrivate *st): + CapCreatorBase(P, st, compute_size(P)) + {} + + private: + enum + { + number_points_per_fan = 6, + number_triangles_per_fan = number_points_per_fan - 2, + number_indices_per_fan = 3 * number_triangles_per_fan, + }; + + static + PointIndexCapSize + compute_size(const PathData &P); + + void + add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const; + }; + + class ThreshWithData + { + public: + ThreshWithData(void): + m_data(nullptr), + m_thresh(-1) + {} + + ThreshWithData(fastuidraw::PainterAttributeData *d, float t): + m_data(d), m_thresh(t) + {} + + static + bool + reverse_compare_against_thresh(const ThreshWithData &lhs, float rhs) + { + return lhs.m_thresh > rhs; + } + + fastuidraw::PainterAttributeData *m_data; + float m_thresh; + }; + + template + class PreparedAttributeData + { + public: + PreparedAttributeData(void): + m_ready(false) + {} + + /* must be called before the first call to data(). + */ + void + mark_as_empty(void) + { + m_ready = true; + } + + const fastuidraw::PainterAttributeData& + data(const PathData &P, const SubsetPrivate *st) + { + if (!m_ready) + { + m_data.set_data(T(P, st)); + m_ready = true; + } + return m_data; + } + + private: + fastuidraw::PainterAttributeData m_data; + bool m_ready; + }; + + class StrokedCapsJoinsPrivate:fastuidraw::noncopyable + { + public: + explicit + StrokedCapsJoinsPrivate(const ContourData &P); + ~StrokedCapsJoinsPrivate(); + + void + create_joins_caps(const ContourData &P); + + template + const fastuidraw::PainterAttributeData& + fetch_create(float thresh, + std::vector &values); + + SubsetPrivate* m_subset; + + PreparedAttributeData m_bevel_joins; + PreparedAttributeData m_miter_clip_joins; + PreparedAttributeData > m_miter_joins; + PreparedAttributeData > m_miter_bevel_joins; + PreparedAttributeData m_square_caps; + PreparedAttributeData m_adjustable_caps; + + PathData m_path_data; + fastuidraw::vecN m_chunk_of_joins; + unsigned int m_chunk_of_caps; + + std::vector m_rounded_joins; + std::vector m_rounded_caps; + + bool m_empty_path; + fastuidraw::PainterAttributeData m_empty_data; + }; + +} + +///////////////////////////////// +// CullingHierarchy methods +CullingHierarchy* +CullingHierarchy:: +create(const ContourData &path_data) +{ + std::vector joins; + std::vector caps; + CullingHierarchy *return_value; + + /* fill joins and caps from the data in path_data */ + for(const PerContourData &C : path_data.m_per_contour_data) + { + caps.push_back(C.cap(0)); + caps.push_back(C.cap(1)); + /* add all but the joins of the closing edge of C, i.e. all but + * the last two joins + */ + for(const PerJoinData &J : C.joins_of_non_closing_edges()) + { + joins.push_back(J); + } + } + + /* now add the joins from the closing edges */ + for(const PerContourData &C : path_data.m_per_contour_data) + { + /* add all but the joins of the closing edge of C, i.e. all but + * the last two joins + */ + for(const PerJoinData &J : C.joins_of_closing_edges()) + { + joins.push_back(J); + } + } + + return_value = FASTUIDRAWnew CullingHierarchy(path_data.m_bounding_box, joins, caps); + return return_value; +} + +CullingHierarchy:: +CullingHierarchy(const fastuidraw::BoundingBox &start_box, + std::vector &joins, std::vector &caps): + m_children(nullptr, nullptr), + m_bb(start_box) +{ + int c; + float mid_point; + + FASTUIDRAWassert(!start_box.empty()); + c = choose_splitting_coordinate(start_box, + fastuidraw::make_c_array(joins), + fastuidraw::make_c_array(caps), + mid_point); + if (c != -1) + { + fastuidraw::vecN, 2> child_boxes; + fastuidraw::vecN, 2> child_joins; + fastuidraw::vecN, 2> child_caps; + + /* NOTE: since the joins come in the order of non-closing first + * and we process them in that order, the non-closing joins + * for child_joins[] will also come first + */ + for(const PerJoinData &J : joins) + { + bool s; + s = J.m_p[c] < mid_point; + child_joins[s].push_back(J); + child_boxes[s].union_point(J.m_p); + } + + for(const PerCapData &C : caps) + { + bool s; + s = C.m_p[c] < mid_point; + child_caps[s].push_back(C); + child_boxes[s].union_point(C.m_p); + } + FASTUIDRAWassert(child_joins[0].size() + child_joins[1].size() == joins.size()); + FASTUIDRAWassert(child_caps[0].size() + child_caps[1].size() == caps.size()); + + if (child_joins[0].size() + child_caps[0].size() < joins.size() + caps.size()) + { + m_children[0] = FASTUIDRAWnew CullingHierarchy(child_boxes[0], child_joins[0], child_caps[0]); + m_children[1] = FASTUIDRAWnew CullingHierarchy(child_boxes[1], child_joins[1], child_caps[1]); + } + } + + if (m_children[0] == nullptr) + { + FASTUIDRAWassert(m_children[1] == nullptr); + + /* steal the data */ + m_caps.swap(caps); + m_joins.swap(joins); + + fastuidraw::c_array all_joins; + all_joins = fastuidraw::make_c_array(m_joins); + + unsigned int non_closing_cnt; + for(non_closing_cnt = 0; + non_closing_cnt < m_joins.size() && !m_joins[non_closing_cnt].m_of_closing_edge; + ++non_closing_cnt) + {} + m_joins_non_closing_edge = all_joins.sub_array(0, non_closing_cnt); + m_joins_closing_edge = all_joins.sub_array(non_closing_cnt); + } +} + +CullingHierarchy:: +~CullingHierarchy(void) +{ + if (m_children[0] != nullptr) + { + FASTUIDRAWdelete(m_children[0]); + } + + if (m_children[1] != nullptr) + { + FASTUIDRAWdelete(m_children[1]); + } +} + +int +CullingHierarchy:: +choose_splitting_coordinate(const fastuidraw::BoundingBox &start_box, + fastuidraw::c_array joins, + fastuidraw::c_array caps, + float &split_value) +{ + if (joins.size() + caps.size() < splitting_threshhold) + { + return -1; + } + + std::vector qs; + fastuidraw::vec2 sz; + int c; + + /* the dimension we choose is whever is larger */ + sz = start_box.max_point() - start_box.min_point(); + c = (sz.x() > sz.y()) ? 0 : 1; + + qs.reserve(joins.size() + caps.size()); + for(const PerJoinData &d : joins) + { + qs.push_back(d.m_p[c]); + } + for(const PerCapData & d : caps) + { + qs.push_back(d.m_p[c]); + } + std::sort(qs.begin(), qs.end()); + + split_value = (qs[qs.size() / 2] + qs[qs.size() / 2 + 1]) * 0.5f; + return c; +} + +////////////////////////////////////////// +// SubsetPrivate methods +SubsetPrivate:: +~SubsetPrivate() +{ + if (m_children[0] != nullptr) + { + FASTUIDRAWdelete(m_children[0]); + } + if (m_children[1] != nullptr) + { + FASTUIDRAWdelete(m_children[1]); + } +} + +SubsetPrivate* +SubsetPrivate:: +create(const CullingHierarchy *src, + CreationValues &out_values, + JoinOrdering &join_ordering, + CapOrdering &cap_ordering) +{ + SubsetPrivate *return_value; + PostProcessVariables vars; + + return_value = FASTUIDRAWnew SubsetPrivate(out_values, join_ordering, cap_ordering, src); + return_value->post_process(vars, out_values, join_ordering, cap_ordering); + return return_value; +} + +void +SubsetPrivate:: +post_process(PostProcessVariables &variables, + const CreationValues &constants, + JoinOrdering &join_ordering, + CapOrdering &cap_ordering) +{ + /* We want the depth to go in the reverse order as the + * draw order. The Draw order is child(0), child(1) + * Thus, we first handle depth child(1) and then child(0). + */ + m_non_closing_joins.m_depth_range.m_begin = variables.m_join_depth; + m_closing_joins.m_depth_range.m_begin = variables.m_closing_join_depth; + + m_caps.m_depth_range.m_begin = variables.m_cap_depth; + + if (have_children()) + { + FASTUIDRAWassert(m_children[0] != nullptr); + FASTUIDRAWassert(m_children[1] != nullptr); + + m_children[1]->post_process(variables, constants, join_ordering, cap_ordering); + m_children[0]->post_process(variables, constants, join_ordering, cap_ordering); + } + else + { + FASTUIDRAWassert(m_children[0] == nullptr); + FASTUIDRAWassert(m_children[1] == nullptr); + + join_ordering.post_process_non_closing(m_non_closing_joins.m_elements, + variables.m_join_depth); + + join_ordering.post_process_closing(constants.m_non_closing_join_chunk_cnt, + m_closing_joins.m_elements, + variables.m_closing_join_depth); + + cap_ordering.post_process(m_caps.m_elements, variables.m_cap_depth); + } + + m_non_closing_joins.m_depth_range.m_end = variables.m_join_depth; + m_closing_joins.m_depth_range.m_end = variables.m_closing_join_depth; + + m_caps.m_depth_range.m_end = variables.m_cap_depth; + + FASTUIDRAWassert(m_non_closing_joins.m_elements.difference() == m_non_closing_joins.m_depth_range.difference()); + FASTUIDRAWassert(m_closing_joins.m_elements.difference() == m_closing_joins.m_depth_range.difference()); + + /* the joins are ordered so that the joins of the non-closing + * edges appear first. + */ + m_closing_joins.m_elements += join_ordering.non_closing_edge().size(); + + /* make the chunks of closing edges come AFTER + * chunks of non-closing edge + */ + m_closing_joins.m_chunk += constants.m_non_closing_join_chunk_cnt; + + m_empty_subset = !m_non_closing_joins.non_empty() + && !m_closing_joins.non_empty() + && !m_caps.non_empty(); +} + +SubsetPrivate:: +SubsetPrivate(CreationValues &out_values, + JoinOrdering &join_ordering, CapOrdering &cap_ordering, + const CullingHierarchy *src): + m_children(nullptr, nullptr), + m_bb(src->bounding_box()) +{ + /* Draw order is: + * child(0) + * child(1) + */ + m_non_closing_joins.m_elements.m_begin = join_ordering.non_closing_edge().size(); + m_closing_joins.m_elements.m_begin = join_ordering.closing_edge().size(); + m_caps.m_elements.m_begin = cap_ordering.caps().size(); + + if (src->has_children()) + { + FASTUIDRAWassert(src->caps().empty()); + FASTUIDRAWassert(src->non_closing_joins().empty()); + FASTUIDRAWassert(src->closing_joins().empty()); + for(unsigned int i = 0; i < 2; ++i) + { + FASTUIDRAWassert(src->child(i) != nullptr); + m_children[i] = FASTUIDRAWnew SubsetPrivate(out_values, join_ordering, cap_ordering, src->child(i)); + } + } + else + { + for(const PerJoinData &J : src->non_closing_joins()) + { + join_ordering.add_join(J, out_values.m_non_closing_join_chunk_cnt); + } + + for(const PerJoinData &J : src->closing_joins()) + { + join_ordering.add_join(J, out_values.m_closing_join_chunk_cnt); + } + + for(const PerCapData &C : src->caps()) + { + cap_ordering.add_cap(C, out_values.m_cap_chunk_cnt); + } + } + + m_non_closing_joins.m_elements.m_end = join_ordering.non_closing_edge().size(); + m_closing_joins.m_elements.m_end = join_ordering.closing_edge().size(); + m_caps.m_elements.m_end = cap_ordering.caps().size(); + + m_non_closing_joins.m_chunk = out_values.m_non_closing_join_chunk_cnt; + m_closing_joins.m_chunk = out_values.m_closing_join_chunk_cnt; + m_caps.m_chunk = out_values.m_cap_chunk_cnt; + + ++out_values.m_non_closing_join_chunk_cnt; + ++out_values.m_closing_join_chunk_cnt; + ++out_values.m_cap_chunk_cnt; +} + +void +SubsetPrivate:: +compute_chunks(bool include_closing_edge, + ScratchSpacePrivate &scratch, + fastuidraw::c_array clip_equations, + const fastuidraw::float3x3 &clip_matrix_local, + const fastuidraw::vec2 &recip_dimensions, + float pixels_additional_room, + float item_space_additional_room, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + bool take_joins_outside_of_region, + ChunkSetPrivate &dst) +{ + scratch.m_adjusted_clip_eqs.resize(clip_equations.size()); + for(unsigned int i = 0; i < clip_equations.size(); ++i) + { + fastuidraw::vec3 c(clip_equations[i]); + float f; + + /* make "w" larger by the named number of pixels. + */ + f = fastuidraw::t_abs(c.x()) * recip_dimensions.x() + + fastuidraw::t_abs(c.y()) * recip_dimensions.y(); + + c.z() += pixels_additional_room * f; + + /* transform clip equations from clip coordinates to + * local coordinates. + */ + scratch.m_adjusted_clip_eqs[i] = c * clip_matrix_local; + } + + dst.reset(); + if (take_joins_outside_of_region) + { + dst.add_join_chunk(m_non_closing_joins); + if (include_closing_edge) + { + dst.add_join_chunk(m_closing_joins); + } + dst.ignore_join_adds(); + } + compute_chunks_implement(include_closing_edge, + scratch, item_space_additional_room, + max_attribute_cnt, max_index_cnt, dst); +} + +void +SubsetPrivate:: +compute_chunks_take_all(bool include_closing_edge, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + ChunkSetPrivate &dst) +{ + if (m_empty_subset) + { + return; + } + + /* + * TODO: take into account max_attribute_cnt/max_indent + * ISSUE: rounded joins/caps have variable attribue/index count, + * solve this by giving cap coefficient and join coefficient + * and multiplying the number of caps and joins by their + * coefficients to get the correct value. + */ + FASTUIDRAWunused(max_attribute_cnt); + FASTUIDRAWunused(max_index_cnt); + + dst.add_join_chunk(m_non_closing_joins); + if (include_closing_edge) + { + dst.add_join_chunk(m_closing_joins); + } + else + { + dst.add_cap_chunk(m_caps); + } +} + +void +SubsetPrivate:: +compute_chunks_implement(bool include_closing_edge, + ScratchSpacePrivate &scratch, + float item_space_additional_room, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + ChunkSetPrivate &dst) +{ + using namespace fastuidraw; + using namespace fastuidraw::detail; + + if (m_bb.empty() || m_empty_subset) + { + return; + } + + /* clip the bounding box of this SubsetPrivate */ + vecN bb; + bool unclipped; + + m_bb.inflated_polygon(bb, item_space_additional_room); + unclipped = clip_against_planes(make_c_array(scratch.m_adjusted_clip_eqs), + bb, scratch.m_clipped_rect, + scratch.m_clip_scratch_floats, + scratch.m_clip_scratch_vec2s); + //completely unclipped. + if (unclipped || !have_children()) + { + compute_chunks_take_all(include_closing_edge, max_attribute_cnt, max_index_cnt, dst); + return; + } + + //completely clipped + if (scratch.m_clipped_rect.empty()) + { + return; + } + + FASTUIDRAWassert(have_children()); + + FASTUIDRAWassert(m_children[0] != nullptr); + FASTUIDRAWassert(m_children[1] != nullptr); + m_children[0]->compute_chunks_implement(include_closing_edge, + scratch, item_space_additional_room, + max_attribute_cnt, max_index_cnt, + dst); + m_children[1]->compute_chunks_implement(include_closing_edge, + scratch, item_space_additional_room, + max_attribute_cnt, max_index_cnt, + dst); +} + +//////////////////////////////////////////////// +// PerJoinData methods +PerJoinData:: +PerJoinData(const fastuidraw::vec2 &p, + float distance_from_previous_join, + const fastuidraw::vec2 &tangent_into_join, + const fastuidraw::vec2 &tangent_leaving_join): + m_of_closing_edge(false), + m_p(p), + m_tangent_into_join(tangent_into_join), + m_tangent_leaving_join(tangent_leaving_join), + m_distance_from_previous_join(distance_from_previous_join), + m_distance_from_contour_start(0.0f), + m_open_contour_length(0.0f), + m_closed_contour_length(0.0f), + m_normal_into_join(-tangent_into_join.y(), tangent_into_join.x()), + m_normal_leaving_join(-tangent_leaving_join.y(), tangent_leaving_join.x()) +{ + /* Explanation: + * We have two curves, a(t) and b(t) with a(1) = b(0) + * The point p0 represents the end of a(t) and the + * point p1 represents the start of b(t). + * + * When stroking we have four auxiliary curves: + * a0(t) = a(t) + w * a_n(t) + * a1(t) = a(t) - w * a_n(t) + * b0(t) = b(t) + w * b_n(t) + * b1(t) = b(t) - w * b_n(t) + * where + * w = width of stroking + * a_n(t) = J( a'(t) ) / || a'(t) || + * b_n(t) = J( b'(t) ) / || b'(t) || + * when + * J(x, y) = (-y, x). + * + * A Bevel join is a triangle that connects + * consists of p, A and B where p is a(1)=b(0), + * A is one of a0(1) or a1(1) and B is one + * of b0(0) or b1(0). Now if we use a0(1) for + * A then we will use b0(0) for B because + * the normals are generated the same way for + * a(t) and b(t). Then, the questions comes + * down to, do we wish to add or subtract the + * normal. That value is represented by m_lambda. + * + * Now to figure out m_lambda. Let q0 be a point + * on a(t) before p=a(1). The q0 is given by + * + * q0 = p - s * m_v0 + * + * and let q1 be a point on b(t) after p=b(0), + * + * q1 = p + t * m_v1 + * + * where both s, t are positive. Let + * + * z = (q0+q1) / 2 + * + * the point z is then on the side of the join + * of the acute angle of the join. + * + * With this in mind, if either of + * or is positive then we want + * to add by -w * n rather than w * n. + * + * Note that: + * + * = 0.5 * < -s * m_v0 + t * m_v1, m_n1 > + * = -0.5 * s * + 0.5 * t * + * = -0.5 * s * + * = -0.5 * s * + * + * and + * + * = 0.5 * < -s * m_v0 + t * m_v1, m_n0 > + * = -0.5 * s * + 0.5 * t * + * = 0.5 * t * + * = 0.5 * t * + * = -0.5 * t * + * + * (the last line because transpose(J) = -J). Notice + * that the sign of and the sign of + * is then the same. + * + * thus m_lambda is positive if is negative. + */ + + m_det = fastuidraw::dot(m_tangent_leaving_join, m_normal_into_join); + if (m_det > 0.0f) + { + m_lambda = -1.0f; + } + else + { + m_lambda = 1.0f; + } +} + +///////////////////////////////////////////////// +// JoinCreatorBase methods +JoinCreatorBase:: +JoinCreatorBase(const PathData &P, const SubsetPrivate *st): + m_ordering(P.m_join_ordering), + m_st(st), + m_num_verts(0), + m_num_indices(0), + m_num_chunks(P.m_number_join_chunks), + m_num_joins(0), + m_post_ctor_initalized_called(false) +{} + +void +JoinCreatorBase:: +post_ctor_initalize(void) +{ + FASTUIDRAWassert(!m_post_ctor_initalized_called); + m_post_ctor_initalized_called = true; + + for(const PerJoinData &J : m_ordering.non_closing_edge()) + { + add_join(m_num_joins, J, m_num_verts, m_num_indices); + ++m_num_joins; + } + + for(const PerJoinData &J : m_ordering.closing_edge()) + { + add_join(m_num_joins, J, m_num_verts, m_num_indices); + ++m_num_joins; + } +} + +void +JoinCreatorBase:: +compute_sizes(unsigned int &num_attributes, + unsigned int &num_indices, + unsigned int &num_attribute_chunks, + unsigned int &num_index_chunks, + unsigned int &number_z_ranges) const +{ + FASTUIDRAWassert(m_post_ctor_initalized_called); + num_attributes = m_num_verts; + num_indices = m_num_indices; + number_z_ranges = num_attribute_chunks = num_index_chunks = m_num_chunks; +} + +void +JoinCreatorBase:: +fill_join(unsigned int join_id, + const PerJoinData &join_data, + unsigned int chunk, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges) const +{ + unsigned int v(vertex_offset), i(index_offset); + + FASTUIDRAWassert(join_id < m_num_joins); + + fill_join_implement(join_id, join_data, pts, depth, indices, vertex_offset, index_offset); + + join_vertex_ranges[join_id].m_begin = v; + join_vertex_ranges[join_id].m_end = vertex_offset; + + join_index_ranges[join_id].m_begin = i; + join_index_ranges[join_id].m_end = index_offset; + + attribute_chunks[chunk] = pts.sub_array(v, vertex_offset - v); + index_chunks[chunk] = indices.sub_array(i, index_offset - i); + index_adjusts[chunk] = -int(v); + zranges[chunk] = fastuidraw::range_type(depth, depth + 1); +} + +void +JoinCreatorBase:: +fill_data(fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) const +{ + unsigned int vertex_offset(0), index_offset(0), join_id(0); + std::vector > jvr(m_num_joins), jir(m_num_joins); + fastuidraw::c_array > join_vertex_ranges, join_index_ranges; + + join_vertex_ranges = fastuidraw::make_c_array(jvr); + join_index_ranges = fastuidraw::make_c_array(jir); + + FASTUIDRAWassert(attribute_data.size() == m_num_verts); + FASTUIDRAWassert(index_data.size() == m_num_indices); + FASTUIDRAWassert(attribute_chunks.size() == m_num_chunks); + FASTUIDRAWassert(index_chunks.size() == m_num_chunks); + FASTUIDRAWassert(zranges.size() == m_num_chunks); + FASTUIDRAWassert(index_adjusts.size() == m_num_chunks); + + /* Note that we reverse the the depth value, we need to do this because + * we want the joins draw first to obscure the joins drawn later. + */ + for(const OrderingEntry &J : m_ordering.non_closing_edge()) + { + fill_join(join_id, J, J.m_chunk, J.m_depth, + attribute_data, index_data, + vertex_offset, index_offset, + attribute_chunks, index_chunks, + zranges, index_adjusts, + join_vertex_ranges, + join_index_ranges); + ++join_id; + } + + for(const OrderingEntry &J : m_ordering.closing_edge()) + { + fill_join(join_id, J, J.m_chunk, J.m_depth, + attribute_data, index_data, + vertex_offset, index_offset, + attribute_chunks, index_chunks, + zranges, index_adjusts, + join_vertex_ranges, + join_index_ranges); + ++join_id; + } + + FASTUIDRAWassert(vertex_offset == m_num_verts); + FASTUIDRAWassert(index_offset == m_num_indices); + set_chunks(m_st, + join_vertex_ranges, join_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); +} + +void +JoinCreatorBase:: +set_chunks(const SubsetPrivate *st, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) +{ + process_chunk(st->non_closing_joins(), + join_vertex_ranges, join_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + + process_chunk(st->closing_joins(), + join_vertex_ranges, join_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + + if (st->have_children()) + { + set_chunks(st->child(0), + join_vertex_ranges, join_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + + set_chunks(st->child(1), + join_vertex_ranges, join_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + } +} + +void +JoinCreatorBase:: +process_chunk(const RangeAndChunk &ch, + fastuidraw::c_array > join_vertex_ranges, + fastuidraw::c_array > join_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) +{ + unsigned int K; + fastuidraw::range_type vr, ir; + + if (ch.m_elements.m_begin < ch.m_elements.m_end) + { + vr.m_begin = join_vertex_ranges[ch.m_elements.m_begin].m_begin; + vr.m_end = join_vertex_ranges[ch.m_elements.m_end - 1].m_end; + + ir.m_begin = join_index_ranges[ch.m_elements.m_begin].m_begin; + ir.m_end = join_index_ranges[ch.m_elements.m_end - 1].m_end; + } + else + { + vr.m_begin = vr.m_end = 0; + ir.m_begin = ir.m_end = 0; + } + + K = ch.m_chunk; + attribute_chunks[K] = attribute_data.sub_array(vr); + index_chunks[K] = index_data.sub_array(ir); + zranges[K] = fastuidraw::range_type(ch.m_depth_range.m_begin, ch.m_depth_range.m_end); + index_adjusts[K] = -int(vr.m_begin); +} + +///////////////////////////////////////////////// +// RoundedJoinCreator::PerRoundedJoin methods +RoundedJoinCreator::PerRoundedJoin:: +PerRoundedJoin(const PerJoinData &J, float thresh): + PerJoinData(J) +{ + /* n0z represents the start point of the rounded join in the complex plane + * as if the join was at the origin, n1z represents the end point of the + * rounded join in the complex plane as if the join was at the origin. + */ + std::complex n0z(m_lambda * n0().x(), m_lambda * n0().y()); + std::complex n1z(m_lambda * n1().x(), m_lambda * n1().y()); + + /* n1z_times_conj_n0z satisfies: + * n1z = n1z_times_conj_n0z * n0z + * i.e. it represents the arc-movement from n0z to n1z + */ + std::complex n1z_times_conj_n0z(n1z * std::conj(n0z)); + + m_arc_start = n0z; + m_delta_theta = std::atan2(n1z_times_conj_n0z.imag(), n1z_times_conj_n0z.real()); + m_num_arc_points = fastuidraw::detail::number_segments_for_tessellation(m_delta_theta, thresh); + m_delta_theta /= static_cast(m_num_arc_points - 1); +} + +void +RoundedJoinCreator::PerRoundedJoin:: +add_data(unsigned int depth, + fastuidraw::c_array pts, + unsigned int &vertex_offset, + fastuidraw::c_array indices, + unsigned int &index_offset) const +{ + unsigned int i, first; + float theta; + fastuidraw::StrokedPoint pt; + + first = vertex_offset; + set_distance_values(&pt); + + pt.m_position = m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = m_p; + pt.m_pre_offset = m_lambda * n0(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + for(i = 1, theta = m_delta_theta; i < m_num_arc_points - 1; ++i, theta += m_delta_theta, ++vertex_offset) + { + float t, c, s; + std::complex cs_as_complex; + + t = static_cast(i) / static_cast(m_num_arc_points - 1); + c = std::cos(theta); + s = std::sin(theta); + cs_as_complex = std::complex(c, s) * m_arc_start; + + pt.m_position = m_p; + pt.m_pre_offset = m_lambda * fastuidraw::vec2(n0().x(), n1().x()); + pt.m_auxiliary_offset = fastuidraw::vec2(t, cs_as_complex.real()); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_rounded_join, depth); + + if (m_lambda * n0().y() < 0.0f) + { + pt.m_packed_data |= fastuidraw::StrokedPoint::normal0_y_sign_mask; + } + + if (m_lambda * n1().y() < 0.0f) + { + pt.m_packed_data |= fastuidraw::StrokedPoint::normal1_y_sign_mask; + } + + if (cs_as_complex.imag() < 0.0f) + { + pt.m_packed_data |= fastuidraw::StrokedPoint::sin_sign_mask; + } + pt.pack_point(&pts[vertex_offset]); + } + + pt.m_position = m_p; + pt.m_pre_offset = m_lambda * n1(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + +/////////////////////////////////////////////////// +// RoundedJoinCreator methods +RoundedJoinCreator:: +RoundedJoinCreator(const PathData &P, + const SubsetPrivate *st, + float thresh): + JoinCreatorBase(P, st), + m_thresh(thresh) +{ + JoinCount J(P.m_join_ordering); + m_per_join_data.reserve(J.m_number_close_joins + J.m_number_non_close_joins); + post_ctor_initalize(); +} + +void +RoundedJoinCreator:: +add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const +{ + FASTUIDRAWunused(join_id); + PerRoundedJoin J(join, m_thresh); + + m_per_join_data.push_back(J); + + /* a triangle fan centered at J.m_p with + * J.m_num_arc_points along an edge + */ + vert_count += (1 + J.m_num_arc_points); + index_count += 3 * (J.m_num_arc_points - 1); +} + +void +RoundedJoinCreator:: +fill_join_implement(unsigned int join_id, const PerJoinData &join, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const +{ + FASTUIDRAWunused(join); + FASTUIDRAWassert(join_id < m_per_join_data.size()); + m_per_join_data[join_id].add_data(depth, pts, vertex_offset, indices, index_offset); +} + + + +/////////////////////////////////////////////////// +// BevelJoinCreator methods +BevelJoinCreator:: +BevelJoinCreator(const PathData &P, const SubsetPrivate *st): + JoinCreatorBase(P, st) +{ + post_ctor_initalize(); +} + +void +BevelJoinCreator:: +add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const +{ + FASTUIDRAWunused(join_id); + FASTUIDRAWunused(join); + + /* one triangle per bevel join */ + vert_count += 3; + index_count += 3; +} + +void +BevelJoinCreator:: +fill_join_implement(unsigned int join_id, const PerJoinData &J, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const +{ + FASTUIDRAWunused(join_id); + + fastuidraw::StrokedPoint pt; + J.set_distance_values(&pt); + + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n0(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset + 0]); + + pt.m_position = J.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset + 1]); + + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n1(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset + 2]); + + add_triangle_fan(vertex_offset, vertex_offset + 3, indices, index_offset); + + vertex_offset += 3; +} + + + +/////////////////////////////////////////////////// +// MiterClipJoinCreator methods +MiterClipJoinCreator:: +MiterClipJoinCreator(const PathData &P, const SubsetPrivate *st): + JoinCreatorBase(P, st) +{ + post_ctor_initalize(); +} + +void +MiterClipJoinCreator:: +add_join(unsigned int join_id, const PerJoinData &join, + unsigned int &vert_count, unsigned int &index_count) const +{ + FASTUIDRAWunused(join_id); + FASTUIDRAWunused(join); + + /* Each join is a triangle fan from 5 points + * (thus 3 triangles, which is 9 indices) + */ + vert_count += 5; + index_count += 9; +} + + +void +MiterClipJoinCreator:: +fill_join_implement(unsigned int join_id, const PerJoinData &J, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const +{ + FASTUIDRAWunused(join_id); + fastuidraw::StrokedPoint pt; + unsigned int first; + + /* The miter point is given by where the two boundary + * curves intersect. The two curves are given by: + * + * a(t) = J.m_p0 + stroke_width * J.m_lamba * J.m_n0 + t * J.m_v0 + * b(s) = J.m_p1 + stroke_width * J.m_lamba * J.m_n1 - s * J.m_v1 + * + * With J.m_0 is the location of the join. + * + * We need to solve a(t) = b(s) and compute that location. + * Linear algebra gives us that: + * + * t = - stroke_width * J.m_lamba * r + * s = - stroke_width * J.m_lamba * r + * where + * r = ( - 1) / + * + * thus + * + * a(t) = J.m_p + stroke_width * ( J.m_lamba * J.m_n0 - r * J.m_lamba * J.m_v0) + * = b(s) + * = J.m_p + stroke_width * ( J.m_lamba * J.m_n1 + r * J.m_lamba * J.m_v1) + */ + + first = vertex_offset; + J.set_distance_values(&pt); + + // join center point. + pt.m_position = J.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // join point from curve into join + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n0(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // miter point A + pt.m_position = J.m_p; + pt.m_pre_offset = J.n0(); + pt.m_auxiliary_offset = J.n1(); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // miter point B + pt.m_position = J.m_p; + pt.m_pre_offset = J.n1(); + pt.m_auxiliary_offset = J.n0(); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join_lambda_negated, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // join point from curve out from join + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n1(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + + +//////////////////////////////////// +// MiterJoinCreator methods +template +MiterJoinCreator:: +MiterJoinCreator(const PathData &P, const SubsetPrivate *st): + JoinCreatorBase(P, st) +{ + post_ctor_initalize(); +} + +template +void +MiterJoinCreator:: +add_join(unsigned int join_id, const PerJoinData &J, + unsigned int &vert_count, unsigned int &index_count) const +{ + /* Each join is a triangle fan from 4 points + * (thus 2 triangles, which is 6 indices) + */ + FASTUIDRAWunused(join_id); + FASTUIDRAWunused(J); + + vert_count += 4; + index_count += 6; +} + +template +void +MiterJoinCreator:: +fill_join_implement(unsigned int join_id, const PerJoinData &J, + fastuidraw::c_array pts, + unsigned int depth, + fastuidraw::c_array indices, + unsigned int &vertex_offset, unsigned int &index_offset) const +{ + FASTUIDRAWunused(join_id); + + fastuidraw::StrokedPoint pt; + unsigned int first; + + first = vertex_offset; + J.set_distance_values(&pt); + + // join center point. + pt.m_position = J.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // join point from curve into join + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n0(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // miter point + pt.m_position = J.m_p; + pt.m_pre_offset = J.n0(); + pt.m_auxiliary_offset = J.n1(); + pt.m_packed_data = pack_data_join(1, tp, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + // join point from curve out from join + pt.m_position = J.m_p; + pt.m_pre_offset = J.m_lambda * J.n1(); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + + +/////////////////////////////////////////////// +// CapCreatorBase methods +CapCreatorBase:: +CapCreatorBase(const PathData &P, + const SubsetPrivate *st, + PointIndexCapSize sz): + m_ordering(P.m_cap_ordering), + m_st(st), + m_num_chunks(P.m_number_cap_chunks), + m_size(sz) +{ +} + +void +CapCreatorBase:: +compute_sizes(unsigned int &num_attributes, + unsigned int &num_indices, + unsigned int &num_attribute_chunks, + unsigned int &num_index_chunks, + unsigned int &number_z_ranges) const +{ + num_attributes = m_size.m_verts; + num_indices = m_size.m_indices; + number_z_ranges = num_attribute_chunks = num_index_chunks = m_num_chunks; +} + +void +CapCreatorBase:: +fill_data(fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) const +{ + unsigned int vertex_offset(0u), index_offset(0u), cap_id(0u); + std::vector > cvr(m_num_chunks), cir(m_num_chunks); + + for(const OrderingEntry &C : m_ordering.caps()) + { + unsigned int v(vertex_offset), i(index_offset); + + add_cap(C, C.m_depth, attribute_data, index_data, vertex_offset, index_offset); + + cvr[cap_id].m_begin = v; + cvr[cap_id].m_end = vertex_offset; + + cir[cap_id].m_begin = i; + cir[cap_id].m_end = index_offset; + + attribute_chunks[C.m_chunk] = attribute_data.sub_array(cvr[cap_id]); + index_chunks[C.m_chunk] = index_data.sub_array(cir[cap_id]); + zranges[C.m_chunk] = fastuidraw::range_type(C.m_depth, C.m_depth + 1); + index_adjusts[C.m_chunk] = -int(v); + + ++cap_id; + } + + FASTUIDRAWassert(vertex_offset == m_size.m_verts); + FASTUIDRAWassert(index_offset == m_size.m_indices); + + set_chunks(m_st, + fastuidraw::make_c_array(cvr), + fastuidraw::make_c_array(cir), + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); +} + +void +CapCreatorBase:: +set_chunks(const SubsetPrivate *st, + fastuidraw::c_array > cap_vertex_ranges, + fastuidraw::c_array > cap_index_ranges, + fastuidraw::c_array attribute_data, + fastuidraw::c_array index_data, + fastuidraw::c_array > attribute_chunks, + fastuidraw::c_array > index_chunks, + fastuidraw::c_array > zranges, + fastuidraw::c_array index_adjusts) +{ + const RangeAndChunk &ch(st->caps()); + fastuidraw::range_type vr, ir; + unsigned int K; + + if (ch.m_elements.m_begin < ch.m_elements.m_end) + { + vr.m_begin = cap_vertex_ranges[ch.m_elements.m_begin].m_begin; + vr.m_end = cap_vertex_ranges[ch.m_elements.m_end - 1].m_end; + + ir.m_begin = cap_index_ranges[ch.m_elements.m_begin].m_begin; + ir.m_end = cap_index_ranges[ch.m_elements.m_end - 1].m_end; + + FASTUIDRAWassert(ch.m_depth_range.m_begin < ch.m_depth_range.m_end); + } + else + { + vr.m_begin = vr.m_end = 0; + ir.m_begin = ir.m_end = 0; + FASTUIDRAWassert(ch.m_depth_range.m_begin == ch.m_depth_range.m_end); + } + + K = ch.m_chunk; + attribute_chunks[K] = attribute_data.sub_array(vr); + index_chunks[K] = index_data.sub_array(ir); + zranges[K] = fastuidraw::range_type(ch.m_depth_range.m_begin, ch.m_depth_range.m_end); + index_adjusts[K] = -int(vr.m_begin); + + if (st->have_children()) + { + set_chunks(st->child(0), + cap_vertex_ranges, cap_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + + set_chunks(st->child(1), + cap_vertex_ranges, cap_index_ranges, + attribute_data, index_data, + attribute_chunks, index_chunks, + zranges, index_adjusts); + } +} + +/////////////////////////////////////////////////// +// RoundedCapCreator methods +RoundedCapCreator:: +RoundedCapCreator(const PathData &P, + const SubsetPrivate *st, + float thresh): + CapCreatorBase(P, st, compute_size(P, thresh)) +{ + m_num_arc_points_per_cap = fastuidraw::detail::number_segments_for_tessellation(M_PI, thresh); + m_delta_theta = static_cast(M_PI) / static_cast(m_num_arc_points_per_cap - 1); +} + +PointIndexCapSize +RoundedCapCreator:: +compute_size(const PathData &P, float thresh) +{ + unsigned int num_caps, num_arc_points_per_cap; + PointIndexCapSize return_value; + + num_arc_points_per_cap = fastuidraw::detail::number_segments_for_tessellation(M_PI, thresh); + + /* each cap is a triangle fan centered at the cap point. */ + num_caps = P.m_cap_ordering.caps().size(); + return_value.m_verts = (1 + num_arc_points_per_cap) * num_caps; + return_value.m_indices = 3 * (num_arc_points_per_cap - 1) * num_caps; + + return return_value; +} + +void +RoundedCapCreator:: +add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const +{ + fastuidraw::vec2 n, v; + unsigned int first, i; + float theta; + fastuidraw::StrokedPoint pt; + + first = vertex_offset; + v = C.m_tangent_into_cap; + n = fastuidraw::vec2(-v.y(), v.x()); + C.set_distance_values(&pt); + + pt.m_position = C.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + for(i = 1, theta = m_delta_theta; i < m_num_arc_points_per_cap - 1; ++i, theta += m_delta_theta, ++vertex_offset) + { + float s, c; + + s = std::sin(theta); + c = std::cos(theta); + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = fastuidraw::vec2(s, c); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_rounded_cap, depth); + pt.pack_point(&pts[vertex_offset]); + } + + pt.m_position = C.m_p; + pt.m_pre_offset = -n; + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + +/////////////////////////////////////////////////// +// SquareCapCreator methods +PointIndexCapSize +SquareCapCreator:: +compute_size(const PathData &P) +{ + PointIndexCapSize return_value; + unsigned int num_caps; + + /* each square cap generates 5 new points + * and 3 triangles (= 9 indices) + */ + num_caps = P.m_cap_ordering.caps().size(); + return_value.m_verts = 5 * num_caps; + return_value.m_indices = 9 * num_caps; + + return return_value; +} + +void +SquareCapCreator:: +add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const +{ + unsigned int first; + fastuidraw::vec2 n, v; + fastuidraw::StrokedPoint pt; + + first = vertex_offset; + v = C.m_tangent_into_cap; + n = fastuidraw::vec2(-v.y(), v.x()); + C.set_distance_values(&pt); + + pt.m_position = C.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = -n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = -n; + pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + +////////////////////////////////////// +// AdjustableCapCreator methods +PointIndexCapSize +AdjustableCapCreator:: +compute_size(const PathData &P) +{ + PointIndexCapSize return_value; + unsigned int num_caps; + + num_caps = P.m_cap_ordering.caps().size(); + return_value.m_verts = number_points_per_fan * num_caps; + return_value.m_indices = number_indices_per_fan * num_caps; + + return return_value; +} + +void +AdjustableCapCreator:: +add_cap(const PerCapData &C, unsigned int depth, + fastuidraw::c_array pts, + fastuidraw::c_array indices, + unsigned int &vertex_offset, + unsigned int &index_offset) const +{ + enum fastuidraw::StrokedPoint::offset_type_t type; + fastuidraw::vec2 n, v; + unsigned int first; + fastuidraw::StrokedPoint pt; + + type = (C.m_is_starting_cap) ? + fastuidraw::StrokedPoint::offset_adjustable_cap_contour_start : + fastuidraw::StrokedPoint::offset_adjustable_cap_contour_end; + + first = vertex_offset; + v = C.m_tangent_into_cap; + n = fastuidraw::vec2(-v.y(), v.x()); + C.set_distance_values(&pt); + + pt.m_position = C.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(0, type, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, type, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(0, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = -n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + pt.m_position = C.m_p; + pt.m_pre_offset = -n; + pt.m_auxiliary_offset = v; + pt.m_packed_data = pack_data(1, type, depth); + pt.pack_point(&pts[vertex_offset]); + ++vertex_offset; + + add_triangle_fan(first, vertex_offset, indices, index_offset); +} + +///////////////////////////////////////////// +// StrokedCapsJoinsPrivate methods +StrokedCapsJoinsPrivate:: +StrokedCapsJoinsPrivate(const ContourData &P): + m_subset(nullptr) +{ + if (!P.m_per_contour_data.empty()) + { + m_empty_path = false; + create_joins_caps(P); + } + else + { + m_empty_path = true; + m_bevel_joins.mark_as_empty(); + m_miter_clip_joins.mark_as_empty(); + m_miter_joins.mark_as_empty(); + m_miter_bevel_joins.mark_as_empty(); + m_square_caps.mark_as_empty(); + m_adjustable_caps.mark_as_empty(); + std::fill(m_chunk_of_joins.begin(), m_chunk_of_joins.end(), 0); + m_chunk_of_caps = 0; + } +} + +StrokedCapsJoinsPrivate:: +~StrokedCapsJoinsPrivate() +{ + for(unsigned int i = 0, endi = m_rounded_joins.size(); i < endi; ++i) + { + FASTUIDRAWdelete(m_rounded_joins[i].m_data); + } + + for(unsigned int i = 0, endi = m_rounded_caps.size(); i < endi; ++i) + { + FASTUIDRAWdelete(m_rounded_caps[i].m_data); + } + + if (!m_empty_path) + { + FASTUIDRAWdelete(m_subset); + } +} + +void +StrokedCapsJoinsPrivate:: +create_joins_caps(const ContourData &P) +{ + CullingHierarchy *s; + SubsetPrivate::CreationValues cnts; + + FASTUIDRAWassert(!m_empty_path); + s = CullingHierarchy::create(P); + m_subset = SubsetPrivate::create(s, cnts, m_path_data.m_join_ordering, m_path_data.m_cap_ordering); + + m_path_data.m_number_join_chunks = cnts.m_non_closing_join_chunk_cnt + cnts.m_closing_join_chunk_cnt; + m_path_data.m_number_cap_chunks = cnts.m_cap_chunk_cnt; + + /* the chunks of the root element have the data for everything. */ + m_chunk_of_joins[fastuidraw::StrokedCapsJoins::all_non_closing] = m_subset->non_closing_joins().m_chunk; + m_chunk_of_joins[fastuidraw::StrokedCapsJoins::all_closing] = m_subset->closing_joins().m_chunk; + + m_chunk_of_caps = m_subset->caps().m_chunk; + + FASTUIDRAWdelete(s); +} + +template +const fastuidraw::PainterAttributeData& +StrokedCapsJoinsPrivate:: +fetch_create(float thresh, std::vector &values) +{ + if (values.empty()) + { + fastuidraw::PainterAttributeData *newD; + newD = FASTUIDRAWnew fastuidraw::PainterAttributeData(); + newD->set_data(T(m_path_data, m_subset, 1.0f)); + values.push_back(ThreshWithData(newD, 1.0f)); + } + + /* we set a hard tolerance of 1e-6. Should we + * set it as a ratio of the bounding box of + * the underlying tessellated path? + */ + thresh = fastuidraw::t_max(thresh, float(1e-6)); + if (values.back().m_thresh <= thresh) + { + std::vector::const_iterator iter; + iter = std::lower_bound(values.begin(), values.end(), thresh, + ThreshWithData::reverse_compare_against_thresh); + FASTUIDRAWassert(iter != values.end()); + FASTUIDRAWassert(iter->m_thresh <= thresh); + FASTUIDRAWassert(iter->m_data != nullptr); + return *iter->m_data; + } + else + { + float t; + t = values.back().m_thresh; + while(t > thresh) + { + fastuidraw::PainterAttributeData *newD; + + t *= 0.5f; + newD = FASTUIDRAWnew fastuidraw::PainterAttributeData(); + newD->set_data(T(m_path_data, m_subset, t)); + values.push_back(ThreshWithData(newD, t)); + } + return *values.back().m_data; + } +} + +////////////////////////////////////////////// +// fastuidraw::StrokedCapsJoins::ScratchSpace methods +fastuidraw::StrokedCapsJoins::ScratchSpace:: +ScratchSpace(void) +{ + m_d = FASTUIDRAWnew ScratchSpacePrivate(); +} + +fastuidraw::StrokedCapsJoins::ScratchSpace:: +~ScratchSpace(void) +{ + ScratchSpacePrivate *d; + d = static_cast(m_d); + FASTUIDRAWdelete(d); + m_d = nullptr; +} + +/////////////////////////////////////// +// ChunkSetPrivate methods +void +ChunkSetPrivate:: +add_join_chunk(const RangeAndChunk &j) +{ + if (j.non_empty() && !m_ignore_join_adds) + { + m_join_chunks.push_back(j.m_chunk); + m_join_ranges.push_back(j.m_elements); + } +} + +void +ChunkSetPrivate:: +add_cap_chunk(const RangeAndChunk &c) +{ + if (c.non_empty()) + { + m_cap_chunks.push_back(c.m_chunk); + } +} + +void +ChunkSetPrivate:: +handle_dashed_evaluator(const fastuidraw::DashEvaluatorBase *dash_evaluator, + const fastuidraw::PainterShaderData::DataBase *dash_data, + const fastuidraw::StrokedCapsJoins &path) +{ + if (dash_evaluator != nullptr) + { + const fastuidraw::PainterAttributeData &joins(path.bevel_joins()); + unsigned int cnt(0); + + m_join_chunks.clear(); + for(const fastuidraw::range_type &R : m_join_ranges) + { + for(unsigned int J = R.m_begin; J < R.m_end; ++J, ++cnt) + { + unsigned int chunk; + fastuidraw::c_array attribs; + + chunk = path.join_chunk(J); + attribs = joins.attribute_data_chunk(chunk); + FASTUIDRAWassert(!attribs.empty()); + FASTUIDRAWassert(attribs.size() == 3); + if (dash_evaluator->covered_by_dash_pattern(dash_data, attribs[0])) + { + m_join_chunks.push_back(chunk); + } + } + } + } +} + +////////////////////////////////////////// +// fastuidraw::StrokedCapsJoins::ChunkSet methods +fastuidraw::StrokedCapsJoins::ChunkSet:: +ChunkSet(void) +{ + m_d = FASTUIDRAWnew ChunkSetPrivate(); +} + +fastuidraw::StrokedCapsJoins::ChunkSet:: +~ChunkSet(void) +{ + ChunkSetPrivate *d; + d = static_cast(m_d); + FASTUIDRAWdelete(d); +} + +fastuidraw::c_array +fastuidraw::StrokedCapsJoins::ChunkSet:: +join_chunks(void) const +{ + ChunkSetPrivate *d; + d = static_cast(m_d); + return d->join_chunks(); +} + +fastuidraw::c_array +fastuidraw::StrokedCapsJoins::ChunkSet:: +cap_chunks(void) const +{ + ChunkSetPrivate *d; + d = static_cast(m_d); + return d->cap_chunks(); +} + +//////////////////////////////////////// +// fastuidraw::StrokedCapsJoins::Builder methods +fastuidraw::StrokedCapsJoins::Builder:: +Builder(void) +{ + m_d = FASTUIDRAWnew ContourData(); +} + +fastuidraw::StrokedCapsJoins::Builder:: +~Builder() +{ + ContourData *d; + d = static_cast(m_d); + FASTUIDRAWdelete(d); +} + +void +fastuidraw::StrokedCapsJoins::Builder:: +begin_contour(const vec2 &start_pt, + const vec2 &path_direction) +{ + ContourData *d; + d = static_cast(m_d); + + d->m_bounding_box.union_point(start_pt); + d->m_per_contour_data.push_back(PerContourData()); + d->m_per_contour_data.back().start(start_pt, path_direction); +} + +void +fastuidraw::StrokedCapsJoins::Builder:: +add_join(const vec2 &join_pt, + float distance_from_previous_join, + const vec2 &direction_into_join, + const vec2 &direction_leaving_join) +{ + ContourData *d; + d = static_cast(m_d); + + FASTUIDRAWassert(!d->m_per_contour_data.empty()); + d->m_bounding_box.union_point(join_pt); + d->m_per_contour_data.back().add_join(join_pt, distance_from_previous_join, + direction_into_join, direction_leaving_join); +} + +void +fastuidraw::StrokedCapsJoins::Builder:: +end_contour(float distance_from_previous_join, + const vec2 &tangent_along_curve) +{ + ContourData *d; + d = static_cast(m_d); + + FASTUIDRAWassert(!d->m_per_contour_data.empty()); + d->m_per_contour_data.back().end(distance_from_previous_join, + tangent_along_curve); +} + +////////////////////////////////////////////////////////////// +// fastuidraw::StrokedCapsJoins methods +fastuidraw::StrokedCapsJoins:: +StrokedCapsJoins(const Builder &B) +{ + ContourData *C; + C = static_cast(B.m_d); + + m_d = FASTUIDRAWnew StrokedCapsJoinsPrivate(*C); +} + +fastuidraw::StrokedCapsJoins:: +~StrokedCapsJoins() +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + FASTUIDRAWdelete(d); + m_d = nullptr; +} + +void +fastuidraw::StrokedCapsJoins:: +compute_chunks(ScratchSpace &scratch_space, + const DashEvaluatorBase *dash_evaluator, + const PainterShaderData::DataBase *dash_data, + c_array clip_equations, + const float3x3 &clip_matrix_local, + const vec2 &recip_dimensions, + float pixels_additional_room, + float item_space_additional_room, + bool include_closing_edges, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + bool take_joins_outside_of_region, + ChunkSet &dst) const +{ + StrokedCapsJoinsPrivate *d; + ScratchSpacePrivate *scratch_space_ptr; + ChunkSetPrivate *chunk_set_ptr; + + d = static_cast(m_d); + scratch_space_ptr = static_cast(scratch_space.m_d); + chunk_set_ptr = static_cast(dst.m_d); + + if (d->m_empty_path) + { + chunk_set_ptr->reset(); + return; + } + + d->m_subset->compute_chunks(include_closing_edges, + *scratch_space_ptr, + clip_equations, + clip_matrix_local, + recip_dimensions, + pixels_additional_room, + item_space_additional_room, + max_attribute_cnt, + max_index_cnt, + take_joins_outside_of_region, + *chunk_set_ptr); + chunk_set_ptr->handle_dashed_evaluator(dash_evaluator, dash_data, *this); +} + +unsigned int +fastuidraw::StrokedCapsJoins:: +number_joins(bool include_joins_of_closing_edge) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_path_data.m_join_ordering.number_joins(include_joins_of_closing_edge); +} + +unsigned int +fastuidraw::StrokedCapsJoins:: +join_chunk(unsigned int J) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_path_data.m_join_ordering.join_chunk(J); +} + +unsigned int +fastuidraw::StrokedCapsJoins:: +chunk_of_joins(enum chunk_selection c) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_chunk_of_joins[c]; +} + +unsigned int +fastuidraw::StrokedCapsJoins:: +chunk_of_caps(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_chunk_of_caps; +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +square_caps(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_square_caps.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +adjustable_caps(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_adjustable_caps.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +bevel_joins(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_bevel_joins.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +miter_clip_joins(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_miter_clip_joins.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +miter_bevel_joins(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_miter_bevel_joins.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +miter_joins(void) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return d->m_miter_joins.data(d->m_path_data, d->m_subset); +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +rounded_joins(float thresh) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + + return (!d->m_empty_path) ? + d->fetch_create(thresh, d->m_rounded_joins) : + d->m_empty_data; +} + +const fastuidraw::PainterAttributeData& +fastuidraw::StrokedCapsJoins:: +rounded_caps(float thresh) const +{ + StrokedCapsJoinsPrivate *d; + d = static_cast(m_d); + return (!d->m_empty_path) ? + d->fetch_create(thresh, d->m_rounded_caps) : + d->m_empty_data; +} diff --git a/src/fastuidraw/tessellated_path.cpp b/src/fastuidraw/tessellated_path.cpp index 9090cc064..71459f841 100644 --- a/src/fastuidraw/tessellated_path.cpp +++ b/src/fastuidraw/tessellated_path.cpp @@ -170,7 +170,8 @@ fastuidraw::TessellatedPath:: TessellatedPath(const Path &input, fastuidraw::TessellatedPath::TessellationParams TP) { - m_d = FASTUIDRAWnew TessellatedPathPrivate(input, TP); + TessellatedPathPrivate *d; + m_d = d = FASTUIDRAWnew TessellatedPathPrivate(input, TP); } fastuidraw::TessellatedPath:: From be4c4227e3ef205b3f9785850b145b1a3587833c Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Fri, 27 Apr 2018 17:11:11 +0300 Subject: [PATCH 12/52] fastuidraw/painter/stroked_path: Use stroked_joins_caps Make use of StrokeCapsJoins in StrokedPath. --- src/fastuidraw/painter/stroked_path.cpp | 2762 ++--------------------- 1 file changed, 189 insertions(+), 2573 deletions(-) diff --git a/src/fastuidraw/painter/stroked_path.cpp b/src/fastuidraw/painter/stroked_path.cpp index 55fe8bcaf..4dcf24b4b 100644 --- a/src/fastuidraw/painter/stroked_path.cpp +++ b/src/fastuidraw/painter/stroked_path.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -51,45 +52,6 @@ namespace StrokedPoint::depth_num_bits, depth); } - inline - uint32_t - pack_data_join(int on_boundary, - enum fastuidraw::StrokedPoint::offset_type_t pt, - uint32_t depth) - { - return pack_data(on_boundary, pt, depth) | fastuidraw::StrokedPoint::join_mask; - } - - void - add_triangle_fan(unsigned int begin, unsigned int end, - fastuidraw::c_array indices, - unsigned int &index_offset) - { - for(unsigned int i = begin + 1; i < end - 1; ++i, index_offset += 3) - { - indices[index_offset + 0] = begin; - indices[index_offset + 1] = i; - indices[index_offset + 2] = i + 1; - } - } - - class JoinSource - { - public: - fastuidraw::vec2 m_pt; - unsigned int m_contour; - unsigned int m_edge_going_into_join; - bool m_of_closing_edge; - }; - - class CapSource - { - public: - fastuidraw::vec2 m_pt; - unsigned int m_contour; - bool m_is_start_cap; - }; - class PerEdgeData { public: @@ -111,148 +73,6 @@ namespace unsigned int m_depth; }; - /* provides in what chunk each Join is located. - */ - class JoinOrdering - { - public: - fastuidraw::c_array > - non_closing_edge(void) const - { - return fastuidraw::make_c_array(m_non_closing_edge); - } - - fastuidraw::c_array > - closing_edge(void) const - { - return fastuidraw::make_c_array(m_closing_edge); - } - - void - add_join(const JoinSource &src, unsigned int &chunk) - { - OrderingEntry J(src, chunk); - if (src.m_of_closing_edge) - { - m_closing_edge.push_back(J); - } - else - { - m_non_closing_edge.push_back(J); - } - ++chunk; - } - - void - post_process_non_closing(fastuidraw::range_type join_range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the joins must come in reverse - * so that higher depth values occlude later elements - */ - R = join_range.difference(); - d = depth + R - 1; - - for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_non_closing_edge.size()); - m_non_closing_edge[i].m_depth = d; - } - depth += R; - } - - void - post_process_closing(unsigned int non_closing_edge_chunk_count, - fastuidraw::range_type join_range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the joins must come in reverse - * so that higher depth values occlude later elements - */ - R = join_range.difference(); - d = depth + R - 1; - - for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_closing_edge.size()); - m_closing_edge[i].m_depth = d; - m_closing_edge[i].m_chunk += non_closing_edge_chunk_count; - } - depth += R; - } - - unsigned int - number_joins(bool include_joins_of_closing_edge) const - { - return include_joins_of_closing_edge ? - m_non_closing_edge.size() + m_closing_edge.size() : - m_non_closing_edge.size(); - } - - unsigned int - join_chunk(unsigned int J) const - { - FASTUIDRAWassert(J < number_joins(true)); - if (J >= m_non_closing_edge.size()) - { - J -= m_non_closing_edge.size(); - return m_closing_edge[J].m_chunk; - } - else - { - return m_non_closing_edge[J].m_chunk; - } - } - - private: - std::vector > m_non_closing_edge; - std::vector > m_closing_edge; - }; - - class CapOrdering - { - public: - fastuidraw::c_array > - caps(void) const - { - return fastuidraw::make_c_array(m_caps); - } - - void - add_cap(const CapSource &src, unsigned int &chunk) - { - OrderingEntry C(src, chunk); - m_caps.push_back(C); - ++chunk; - } - - void - post_process(fastuidraw::range_type range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the caps must come in reverse - * so that higher depth values occlude later elements - */ - R = range.difference(); - d = depth + R - 1; - for(unsigned int i = range.m_begin; i < range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_caps.size()); - m_caps[i].m_depth = d; - } - depth += R; - } - - private: - std::vector > m_caps; - }; - class PerContourData { public: @@ -299,11 +119,6 @@ namespace { public: ContourData m_contour_data; - - JoinOrdering m_join_ordering; - unsigned int m_number_join_chunks; - CapOrdering m_cap_ordering; - unsigned int m_number_cap_chunks; }; class SingleSubEdge @@ -382,24 +197,6 @@ namespace return m_sub_edges.m_closing; } - fastuidraw::c_array - non_closing_joins(void) const - { - return m_joins.m_non_closing; - } - - fastuidraw::c_array - closing_joins(void) const - { - return m_joins.m_closing; - } - - fastuidraw::c_array - caps(void) const - { - return fastuidraw::make_c_array(m_caps); - } - const fastuidraw::BoundingBox& bounding_box(void) const { @@ -444,9 +241,7 @@ namespace }; SubEdgeCullingHierarchy(const fastuidraw::BoundingBox &start_box, - std::vector &data, unsigned int num_non_closing_edges, - std::vector &joins, unsigned int num_non_closing_joins, - std::vector &caps); + std::vector &data, unsigned int num_non_closing_edges); /* a value of -1 means to NOT split. */ @@ -460,9 +255,7 @@ namespace void create_lists(const fastuidraw::TessellatedPath &P, ContourData &contour_data, std::vector &data, unsigned int &num_non_closing_edges, - fastuidraw::BoundingBox &bx, - std::vector &joins, unsigned int &num_non_closing_joins, - std::vector &caps); + fastuidraw::BoundingBox &bx); static void @@ -476,6 +269,17 @@ namespace void check_closing_at_end(const std::vector &data, unsigned int num_non_closing); + static + float + compute_lambda(const fastuidraw::vec2 &n0, const fastuidraw::vec2 &n1) + { + fastuidraw::vec2 v1(n1.y(), -n1.x()); + float d; + + d = fastuidraw::dot(v1, n0); + return (d > 0.0f) ? -1.0f : 1.0f; + } + /* tolerance for normal computation when creating edge list. */ static const float sm_mag_tol; @@ -484,14 +288,6 @@ namespace */ fastuidraw::vecN m_children; - /* Caps inside, only non-empty if has no children. - */ - std::vector m_caps; - - /* Joins inside, only non-empty if has no children. - */ - PartitionedData m_joins; - /* what edges of this, only non-empty if has no children. */ PartitionedData m_sub_edges; @@ -509,6 +305,7 @@ namespace fastuidraw::vecN, 2> m_clip_scratch_vec2s; std::vector m_clip_scratch_floats; + fastuidraw::StrokedCapsJoins::ScratchSpace m_caps_joins; }; class EdgeRanges @@ -549,83 +346,28 @@ namespace } }; - class RangeAndChunk - { - public: - /* what range of Joins/Caps hit by the chunk. - */ - fastuidraw::range_type m_elements; - - /* depth range of Joins/Caps hit - */ - fastuidraw::range_type m_depth_range; - - /* what the chunk is - */ - unsigned int m_chunk; - - bool - non_empty(void) const - { - return m_depth_range.m_end > m_depth_range.m_begin; - } - }; - class ChunkSetPrivate:fastuidraw::noncopyable { public: void reset(void) { - m_ignore_join_adds = false; m_edge_chunks.clear(); - m_join_chunks.clear(); - m_join_ranges.clear(); - m_cap_chunks.clear(); } void add_edge_chunk(const EdgeRanges &ed); - void - add_join_chunk(const RangeAndChunk &j); - - void - add_cap_chunk(const RangeAndChunk &c); - fastuidraw::c_array edge_chunks(void) const { return fastuidraw::make_c_array(m_edge_chunks); } - fastuidraw::c_array - join_chunks(void) const - { - return fastuidraw::make_c_array(m_join_chunks); - } - - fastuidraw::c_array - cap_chunks(void) const - { - return fastuidraw::make_c_array(m_cap_chunks); - } - - void - ignore_join_adds(void) - { - m_ignore_join_adds = true; - } - - void - handle_dashed_evaluator(const fastuidraw::DashEvaluatorBase *dash_evaluator, - const fastuidraw::PainterShaderData::DataBase *dash_data, - const fastuidraw::StrokedPath &path); + fastuidraw::StrokedCapsJoins::ChunkSet m_caps_joins; private: - std::vector m_edge_chunks, m_join_chunks, m_cap_chunks; - std::vector > m_join_ranges; - bool m_ignore_join_adds; + std::vector m_edge_chunks; }; /* Subset of a StrokedPath. Edges are to be placed into @@ -655,10 +397,7 @@ namespace m_non_closing_edge_chunk_cnt(0), m_closing_edge_vertex_cnt(0), m_closing_edge_index_cnt(0), - m_closing_edge_chunk_cnt(0), - m_non_closing_join_chunk_cnt(0), - m_closing_join_chunk_cnt(0), - m_cap_chunk_cnt(0) + m_closing_edge_chunk_cnt(0) {} unsigned int m_non_closing_edge_vertex_cnt; @@ -668,19 +407,12 @@ namespace unsigned int m_closing_edge_vertex_cnt; unsigned int m_closing_edge_index_cnt; unsigned int m_closing_edge_chunk_cnt; - - unsigned int m_non_closing_join_chunk_cnt; - unsigned int m_closing_join_chunk_cnt; - - unsigned int m_cap_chunk_cnt; }; static StrokedPathSubset* create(const SubEdgeCullingHierarchy *src, - CreationValues &out_values, - JoinOrdering &join_ordering, - CapOrdering &cap_ordering); + CreationValues &out_values); ~StrokedPathSubset(); @@ -694,7 +426,6 @@ namespace float item_space_additional_room, unsigned int max_attribute_cnt, unsigned int max_index_cnt, - bool take_joins_outside_of_region, ChunkSetPrivate &dst); bool @@ -729,44 +460,19 @@ namespace return m_closing_edges; } - const RangeAndChunk& - non_closing_joins(void) const - { - return m_non_closing_joins; - } - - const RangeAndChunk& - closing_joins(void) const - { - return m_closing_joins; - } - - const RangeAndChunk& - caps(void) const - { - return m_caps; - } - private: class PostProcessVariables { public: PostProcessVariables(void): m_edge_depth(0), - m_closing_edge_depth(0), - m_join_depth(0), - m_closing_join_depth(0), - m_cap_depth(0) + m_closing_edge_depth(0) {} unsigned int m_edge_depth, m_closing_edge_depth; - unsigned int m_join_depth, m_closing_join_depth; - unsigned int m_cap_depth; }; StrokedPathSubset(CreationValues &out_values, - JoinOrdering &join_ordering, - CapOrdering &cap_ordering, const SubEdgeCullingHierarchy *src); void @@ -790,24 +496,13 @@ namespace unsigned int &index_cnt); void post_process(PostProcessVariables &variables, - const CreationValues &constants, - JoinOrdering &join_ordering, - CapOrdering &cap_ordering); + const CreationValues &constants); fastuidraw::vecN m_children; - /* book keeping for edges. - */ + /* book keeping for edges. */ EdgeRanges m_non_closing_edges, m_closing_edges; - /* book keeping for joins - */ - RangeAndChunk m_non_closing_joins, m_closing_joins; - - /* book keeping for caps - */ - RangeAndChunk m_caps; - fastuidraw::BoundingBox m_bb; bool m_empty_subset; @@ -868,555 +563,72 @@ namespace unsigned int m_total_number_chunks; }; - class JoinCount + template + class PreparedAttributeData { public: - explicit - JoinCount(const ContourData &P); + PreparedAttributeData(void): + m_ready(false) + {} - unsigned int m_number_close_joins; - unsigned int m_number_non_close_joins; - }; + /* must be called before the first call to data(). + */ + void + mark_as_empty(void) + { + m_ready = true; + } - class CommonJoinData - { - public: - CommonJoinData(const fastuidraw::vec2 &p0, - const fastuidraw::vec2 &n0, - const fastuidraw::vec2 &p1, - const fastuidraw::vec2 &n1, - float distance_from_edge_start, - float distance_from_contour_start, - float edge_length, - float open_contour_length, - float closed_contour_length); - - float m_det, m_lambda; - fastuidraw::vec2 m_p0, m_v0, m_n0; - fastuidraw::vec2 m_p1, m_v1, m_n1; - float m_distance_from_edge_start; - float m_distance_from_contour_start; - float m_edge_length; - float m_open_contour_length; - float m_closed_contour_length; + const fastuidraw::PainterAttributeData& + data(const PathData &P, const StrokedPathSubset *st) + { + if (!m_ready) + { + m_data.set_data(T(P, st)); + m_ready = true; + } + return m_data; + } - static - float - compute_lambda(const fastuidraw::vec2 &n0, const fastuidraw::vec2 &n1); + private: + fastuidraw::PainterAttributeData m_data; + bool m_ready; }; - class JoinCreatorBase:public fastuidraw::PainterAttributeDataFiller + class StrokedPathPrivate:fastuidraw::noncopyable { public: explicit - JoinCreatorBase(const PathData &P, - const StrokedPathSubset *st); - - virtual - ~JoinCreatorBase() {} - - virtual - void - compute_sizes(unsigned int &num_attributes, - unsigned int &num_indices, - unsigned int &num_attribute_chunks, - unsigned int &num_index_chunks, - unsigned int &number_z_ranges) const; - - virtual - void - fill_data(fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) const; - - protected: - - void - post_ctor_initalize(void); - - private: + StrokedPathPrivate(const fastuidraw::TessellatedPath &P, + const fastuidraw::StrokedCapsJoins::Builder &b); + ~StrokedPathPrivate(); void - fill_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int chunk, unsigned int depth, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges) const; + create_edges(const fastuidraw::TessellatedPath &P); static void - set_chunks(const StrokedPathSubset *st, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts); + ready_builder(const fastuidraw::TessellatedPath *tess, + fastuidraw::StrokedCapsJoins::Builder &b); static void - process_chunk(const RangeAndChunk &ch, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts); - - virtual - void - add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const = 0; - - virtual - void - fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const = 0; - - const ContourData &m_P; - const JoinOrdering &m_ordering; - const StrokedPathSubset *m_st; - unsigned int m_num_verts, m_num_indices, m_num_chunks, m_num_joins; - bool m_post_ctor_initalized_called; - }; - - - class RoundedJoinCreator:public JoinCreatorBase - { - public: - RoundedJoinCreator(const PathData &P, - const StrokedPathSubset *st, - float thresh); - - private: - - class PerJoinData:public CommonJoinData - { - public: - PerJoinData(const fastuidraw::TessellatedPath::point &p0, - const fastuidraw::TessellatedPath::point &p1, - const fastuidraw::vec2 &n0_from_stroking, - const fastuidraw::vec2 &n1_from_stroking, - float thresh); + ready_builder_contour(const fastuidraw::TessellatedPath *tess, + unsigned int contour, + fastuidraw::StrokedCapsJoins::Builder &b); - void - add_data(unsigned int depth, - fastuidraw::c_array pts, - unsigned int &vertex_offset, - fastuidraw::c_array indices, - unsigned int &index_offset) const; - - std::complex m_arc_start; - float m_delta_theta; - unsigned int m_num_arc_points; - }; + fastuidraw::StrokedCapsJoins m_caps_joins; + StrokedPathSubset* m_subset; + fastuidraw::PainterAttributeData m_edges; - virtual - void - add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const; + PathData m_path_data; + fastuidraw::vecN m_chunk_of_edges; - virtual - void - fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const; - - float m_thresh; - mutable std::vector m_per_join_data; + bool m_empty_path; + fastuidraw::PainterAttributeData m_empty_data; }; - class BevelJoinCreator:public JoinCreatorBase - { - public: - explicit - BevelJoinCreator(const PathData &P, - const StrokedPathSubset *st); - - private: - - virtual - void - add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const; - - virtual - void - fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const; - - mutable std::vector m_n0, m_n1; - }; - - class MiterClipJoinCreator:public JoinCreatorBase - { - public: - explicit - MiterClipJoinCreator(const PathData &P, - const StrokedPathSubset *st); - - private: - virtual - void - add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const; - - virtual - void - fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const; - - mutable std::vector m_n0, m_n1; - }; - - template - class MiterJoinCreator:public JoinCreatorBase - { - public: - explicit - MiterJoinCreator(const PathData &P, - const StrokedPathSubset *st); - - private: - virtual - void - add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const; - - virtual - void - fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const; - - mutable std::vector m_n0, m_n1; - }; - - class PointIndexCapSize - { - public: - PointIndexCapSize(void): - m_verts(0), - m_indices(0) - {} - - unsigned int m_verts, m_indices; - }; - - class CommonCapData - { - public: - CommonCapData(bool is_start_cap, - const fastuidraw::vec2 &src_pt, - const fastuidraw::vec2 &normal_from_stroking): - m_is_start_cap(is_start_cap), - m_lambda((is_start_cap) ? -1.0f : 1.0f), - m_p(src_pt), - m_n(normal_from_stroking) - { - //caps at the start are on the "other side" - m_v = fastuidraw::vec2(m_n.y(), -m_n.x()); - m_v *= m_lambda; - m_n *= m_lambda; - } - - bool m_is_start_cap; - float m_lambda; - fastuidraw::vec2 m_p, m_n, m_v; - }; - - class CapCreatorBase:public fastuidraw::PainterAttributeDataFiller - { - public: - CapCreatorBase(const PathData &P, - const StrokedPathSubset *st, - PointIndexCapSize sz); - - virtual - ~CapCreatorBase() - {} - - virtual - void - compute_sizes(unsigned int &num_attributes, - unsigned int &num_indices, - unsigned int &num_attribute_chunks, - unsigned int &num_index_chunks, - unsigned int &number_z_ranges) const; - - virtual - void - fill_data(fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) const; - - private: - virtual - void - add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p0, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const = 0; - - static - void - set_chunks(const StrokedPathSubset *st, - fastuidraw::c_array > cap_vertex_ranges, - fastuidraw::c_array > cap_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts); - - const ContourData &m_P; - const CapOrdering &m_ordering; - const StrokedPathSubset *m_st; - - unsigned int m_num_chunks; - PointIndexCapSize m_size; - }; - - class RoundedCapCreator:public CapCreatorBase - { - public: - RoundedCapCreator(const PathData &P, - const StrokedPathSubset *st, - float thresh); - - private: - static - PointIndexCapSize - compute_size(const ContourData &P, float thresh); - - virtual - void - add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p0, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const; - - float m_delta_theta; - unsigned int m_num_arc_points_per_cap; - }; - - class SquareCapCreator:public CapCreatorBase - { - public: - explicit - SquareCapCreator(const PathData &P, - const StrokedPathSubset *st): - CapCreatorBase(P, st, compute_size(P.m_contour_data)) - {} - - private: - static - PointIndexCapSize - compute_size(const ContourData &P); - - void - add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p0, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const; - }; - - class AdjustableCapCreator:public CapCreatorBase - { - public: - AdjustableCapCreator(const PathData &P, - const StrokedPathSubset *st): - CapCreatorBase(P, st, compute_size(P.m_contour_data)) - {} - - private: - enum - { - number_points_per_fan = 6, - number_triangles_per_fan = number_points_per_fan - 2, - number_indices_per_fan = 3 * number_triangles_per_fan, - }; - - static - void - pack_fan(bool entering_contour, - enum fastuidraw::StrokedPoint::offset_type_t type, - const fastuidraw::TessellatedPath::point &edge_pt, - const fastuidraw::vec2 &stroking_normal, - unsigned int depth, - fastuidraw::c_array pts, - unsigned int &vertex_offset, - fastuidraw::c_array indices, - unsigned int &index_offset); - - static - PointIndexCapSize - compute_size(const ContourData &P); - - void - add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p0, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const; - }; - - class ThreshWithData - { - public: - ThreshWithData(void): - m_data(nullptr), - m_thresh(-1) - {} - - ThreshWithData(fastuidraw::PainterAttributeData *d, float t): - m_data(d), m_thresh(t) - {} - - static - bool - reverse_compare_against_thresh(const ThreshWithData &lhs, float rhs) - { - return lhs.m_thresh > rhs; - } - - fastuidraw::PainterAttributeData *m_data; - float m_thresh; - }; - - template - class PreparedAttributeData - { - public: - PreparedAttributeData(void): - m_ready(false) - {} - - /* must be called before the first call to data(). - */ - void - mark_as_empty(void) - { - m_ready = true; - } - - const fastuidraw::PainterAttributeData& - data(const PathData &P, const StrokedPathSubset *st) - { - if (!m_ready) - { - m_data.set_data(T(P, st)); - m_ready = true; - } - return m_data; - } - - private: - fastuidraw::PainterAttributeData m_data; - bool m_ready; - }; - - class StrokedPathPrivate:fastuidraw::noncopyable - { - public: - explicit - StrokedPathPrivate(const fastuidraw::TessellatedPath &P); - ~StrokedPathPrivate(); - - void - create_edges(const fastuidraw::TessellatedPath &P); - - template - const fastuidraw::PainterAttributeData& - fetch_create(float thresh, - std::vector &values); - - StrokedPathSubset* m_subset; - fastuidraw::PainterAttributeData m_edges; - - PreparedAttributeData m_bevel_joins; - PreparedAttributeData m_miter_clip_joins; - PreparedAttributeData > m_miter_joins; - PreparedAttributeData > m_miter_bevel_joins; - PreparedAttributeData m_square_caps; - PreparedAttributeData m_adjustable_caps; - - PathData m_path_data; - fastuidraw::vecN m_chunk_of_joins; - fastuidraw::vecN m_chunk_of_edges; - unsigned int m_chunk_of_caps; - - std::vector m_rounded_joins; - std::vector m_rounded_caps; - - bool m_empty_path; - fastuidraw::PainterAttributeData m_empty_data; - }; - -} +} /////////////////////////////////////// // SingleSubEdge::point methods @@ -1485,17 +697,12 @@ SubEdgeCullingHierarchy:: create(const fastuidraw::TessellatedPath &P, ContourData &path_data) { std::vector data; - std::vector joins; - std::vector caps; fastuidraw::BoundingBox bx; - unsigned int num_non_closing_edges, num_non_closing_joins; + unsigned int num_non_closing_edges; SubEdgeCullingHierarchy *return_value; - create_lists(P, path_data, - data, num_non_closing_edges, bx, - joins, num_non_closing_joins, caps); - return_value = FASTUIDRAWnew SubEdgeCullingHierarchy(bx, data, num_non_closing_edges, - joins, num_non_closing_joins, caps); + create_lists(P, path_data, data, num_non_closing_edges, bx); + return_value = FASTUIDRAWnew SubEdgeCullingHierarchy(bx, data, num_non_closing_edges); return return_value; } @@ -1503,9 +710,7 @@ void SubEdgeCullingHierarchy:: create_lists(const fastuidraw::TessellatedPath &P, ContourData &path_data, std::vector &data, unsigned int &num_non_closing_edges, - fastuidraw::BoundingBox &bx, - std::vector &joins, unsigned int &num_non_closing_joins, - std::vector &caps) + fastuidraw::BoundingBox &bx) { path_data.m_per_contour_data.resize(P.number_contours()); @@ -1519,59 +724,16 @@ create_lists(const fastuidraw::TessellatedPath &P, ContourData &path_data, for(unsigned int e = 0, ende = P.number_edges(o); e + 1 < ende; ++e) { process_edge(P, path_data, o, e, data, bx); - - if (e + 2 != ende) - { - JoinSource J; - J.m_contour = o; - J.m_edge_going_into_join = e; - J.m_of_closing_edge = false; - J.m_pt = path_data.m_per_contour_data[o].m_edge_data_store[e].m_end_pt.m_p; - joins.push_back(J); - } } } num_non_closing_edges = data.size(); - num_non_closing_joins = joins.size(); - for(unsigned int o = 0; o < P.number_contours(); ++o) { if (P.number_edges(o) > 0) { process_edge(P, path_data, o, P.number_edges(o) - 1, data, bx); - - if (P.number_edges(o) >= 2) - { - JoinSource J; - unsigned int e; - - e = P.number_edges(o) - 2; - J.m_contour = o; - J.m_edge_going_into_join = e; - J.m_of_closing_edge = true; - J.m_pt = path_data.m_per_contour_data[o].m_edge_data_store[e].m_end_pt.m_p; - joins.push_back(J); - - e = P.number_edges(o) - 1; - J.m_contour = o; - J.m_edge_going_into_join = e; - J.m_of_closing_edge = true; - J.m_pt = path_data.m_per_contour_data[o].m_edge_data_store[e].m_end_pt.m_p; - joins.push_back(J); - } } - - CapSource C0, C1; - C0.m_contour = o; - C0.m_is_start_cap = true; - C0.m_pt = P.unclosed_contour_point_data(o).front().m_p; - caps.push_back(C0); - - C1.m_contour = o; - C1.m_is_start_cap = false; - C1.m_pt = P.unclosed_contour_point_data(o).back().m_p; - caps.push_back(C1); } } @@ -1620,7 +782,7 @@ process_edge(const fastuidraw::TessellatedPath &P, ContourData &path_data, } else { - sub_edge.m_bevel_lambda = CommonJoinData::compute_lambda(last_normal, normal); + sub_edge.m_bevel_lambda = compute_lambda(last_normal, normal); sub_edge.m_has_bevel = true; sub_edge.m_bevel_normal = last_normal; } @@ -1683,9 +845,7 @@ check_closing_at_end(const std::vector &data, unsigned int num_non_closing) SubEdgeCullingHierarchy:: SubEdgeCullingHierarchy(const fastuidraw::BoundingBox &start_box, - std::vector &edges, unsigned int num_non_closing_edges, - std::vector &joins, unsigned int num_non_closing_joins, - std::vector &caps): + std::vector &edges, unsigned int num_non_closing_edges): m_children(nullptr, nullptr), m_bb(start_box) { @@ -1694,36 +854,15 @@ SubEdgeCullingHierarchy(const fastuidraw::BoundingBox &start_box, FASTUIDRAWassert(!start_box.empty()); check_closing_at_end(edges, num_non_closing_edges); - check_closing_at_end(joins, num_non_closing_joins); c = choose_splitting_coordinate(start_box, fastuidraw::make_c_array(edges), mid_point); if (c != -1) { fastuidraw::vecN, 2> child_boxes; fastuidraw::vecN, 2> child_sub_edges; - fastuidraw::vecN, 2> child_joins; - fastuidraw::vecN, 2> child_caps; fastuidraw::vecN child_num_non_closing_edges(0, 0); fastuidraw::vecN child_num_non_closing_joins(0, 0); - for(const JoinSource &J : joins) - { - bool s; - s = J.m_pt[c] < mid_point; - child_joins[s].push_back(J); - if (!J.m_of_closing_edge) - { - ++child_num_non_closing_joins[s]; - } - } - - for(const CapSource &C : caps) - { - bool s; - s = C.m_pt[c] < mid_point; - child_caps[s].push_back(C); - } - for(const SingleSubEdge &sub_edge : edges) { bool sA, sB; @@ -1758,21 +897,13 @@ SubEdgeCullingHierarchy(const fastuidraw::BoundingBox &start_box, } } - m_children[0] = FASTUIDRAWnew SubEdgeCullingHierarchy(child_boxes[0], - child_sub_edges[0], child_num_non_closing_edges[0], - child_joins[0], child_num_non_closing_joins[0], - child_caps[0]); - m_children[1] = FASTUIDRAWnew SubEdgeCullingHierarchy(child_boxes[1], - child_sub_edges[1], child_num_non_closing_edges[1], - child_joins[1], child_num_non_closing_joins[1], - child_caps[1]); + m_children[0] = FASTUIDRAWnew SubEdgeCullingHierarchy(child_boxes[0], child_sub_edges[0], child_num_non_closing_edges[0]); + m_children[1] = FASTUIDRAWnew SubEdgeCullingHierarchy(child_boxes[1], child_sub_edges[1], child_num_non_closing_edges[1]); } else { /* steal the data */ - m_caps.swap(caps); m_sub_edges.init(edges, num_non_closing_edges); - m_joins.init(joins, num_non_closing_joins); } } @@ -1874,24 +1005,19 @@ StrokedPathSubset:: StrokedPathSubset* StrokedPathSubset:: create(const SubEdgeCullingHierarchy *src, - CreationValues &out_values, - JoinOrdering &join_ordering, - CapOrdering &cap_ordering) + CreationValues &out_values) { StrokedPathSubset *return_value; PostProcessVariables vars; - return_value = FASTUIDRAWnew StrokedPathSubset(out_values, join_ordering, cap_ordering, src); - return_value->post_process(vars, out_values, join_ordering, cap_ordering); + return_value = FASTUIDRAWnew StrokedPathSubset(out_values, src); + return_value->post_process(vars, out_values); return return_value; } void StrokedPathSubset:: -post_process(PostProcessVariables &variables, - const CreationValues &constants, - JoinOrdering &join_ordering, - CapOrdering &cap_ordering) +post_process(PostProcessVariables &variables, const CreationValues &constants) { /* We want the depth to go in the reverse order as the * draw order. The Draw order is child(0), child(1) @@ -1900,11 +1026,6 @@ post_process(PostProcessVariables &variables, m_non_closing_edges.m_depth_range.m_begin = variables.m_edge_depth; m_closing_edges.m_depth_range.m_begin = variables.m_closing_edge_depth; - m_non_closing_joins.m_depth_range.m_begin = variables.m_join_depth; - m_closing_joins.m_depth_range.m_begin = variables.m_closing_join_depth; - - m_caps.m_depth_range.m_begin = variables.m_cap_depth; - if (have_children()) { FASTUIDRAWassert(m_children[0] != nullptr); @@ -1912,8 +1033,8 @@ post_process(PostProcessVariables &variables, FASTUIDRAWassert(m_non_closing_edges.m_src.empty()); FASTUIDRAWassert(m_closing_edges.m_src.empty()); - m_children[1]->post_process(variables, constants, join_ordering, cap_ordering); - m_children[0]->post_process(variables, constants, join_ordering, cap_ordering); + m_children[1]->post_process(variables, constants); + m_children[0]->post_process(variables, constants); } else { @@ -1922,27 +1043,10 @@ post_process(PostProcessVariables &variables, variables.m_edge_depth += m_non_closing_edges.m_src.size(); variables.m_closing_edge_depth += m_closing_edges.m_src.size(); - - join_ordering.post_process_non_closing(m_non_closing_joins.m_elements, - variables.m_join_depth); - - join_ordering.post_process_closing(constants.m_non_closing_join_chunk_cnt, - m_closing_joins.m_elements, - variables.m_closing_join_depth); - - cap_ordering.post_process(m_caps.m_elements, variables.m_cap_depth); } m_non_closing_edges.m_depth_range.m_end = variables.m_edge_depth; m_closing_edges.m_depth_range.m_end = variables.m_closing_edge_depth; - m_non_closing_joins.m_depth_range.m_end = variables.m_join_depth; - m_closing_joins.m_depth_range.m_end = variables.m_closing_join_depth; - - m_caps.m_depth_range.m_end = variables.m_cap_depth; - - FASTUIDRAWassert(m_non_closing_joins.m_elements.difference() == m_non_closing_joins.m_depth_range.difference()); - FASTUIDRAWassert(m_closing_joins.m_elements.difference() == m_closing_joins.m_depth_range.difference()); - /* make the closing edge chunks start after the * non-closing edge chunks. */ @@ -1954,26 +1058,12 @@ post_process(PostProcessVariables &variables, m_closing_edges.m_vertex_data_range += constants.m_non_closing_edge_vertex_cnt; m_closing_edges.m_index_data_range += constants.m_non_closing_edge_index_cnt; - /* the joins are ordered so that the joins of the non-closing - * edges appear first. - */ - m_closing_joins.m_elements += join_ordering.non_closing_edge().size(); - - /* make the chunks of closing edges come AFTER - * chunks of non-closing edge - */ - m_closing_joins.m_chunk += constants.m_non_closing_join_chunk_cnt; - m_empty_subset = !m_non_closing_edges.non_empty() - && !m_non_closing_joins.non_empty() - && !m_closing_edges.non_empty() - && !m_closing_joins.non_empty(); + && !m_closing_edges.non_empty(); } StrokedPathSubset:: -StrokedPathSubset(CreationValues &out_values, - JoinOrdering &join_ordering, CapOrdering &cap_ordering, - const SubEdgeCullingHierarchy *src): +StrokedPathSubset(CreationValues &out_values, const SubEdgeCullingHierarchy *src): m_children(nullptr, nullptr), m_bb(src->bounding_box()) { @@ -1987,19 +1077,12 @@ StrokedPathSubset(CreationValues &out_values, m_closing_edges.m_vertex_data_range.m_begin = out_values.m_closing_edge_vertex_cnt; m_closing_edges.m_index_data_range.m_begin = out_values.m_closing_edge_index_cnt; - m_non_closing_joins.m_elements.m_begin = join_ordering.non_closing_edge().size(); - m_closing_joins.m_elements.m_begin = join_ordering.closing_edge().size(); - m_caps.m_elements.m_begin = cap_ordering.caps().size(); - if (src->has_children()) { - FASTUIDRAWassert(src->caps().empty()); - FASTUIDRAWassert(src->non_closing_joins().empty()); - FASTUIDRAWassert(src->closing_joins().empty()); for(unsigned int i = 0; i < 2; ++i) { FASTUIDRAWassert(src->child(i) != nullptr); - m_children[i] = FASTUIDRAWnew StrokedPathSubset(out_values, join_ordering, cap_ordering, src->child(i)); + m_children[i] = FASTUIDRAWnew StrokedPathSubset(out_values, src->child(i)); } } else @@ -2013,21 +1096,6 @@ StrokedPathSubset(CreationValues &out_values, increment_vertices_indices(m_closing_edges.m_src, out_values.m_closing_edge_vertex_cnt, out_values.m_closing_edge_index_cnt); - - for(const JoinSource &J : src->non_closing_joins()) - { - join_ordering.add_join(J, out_values.m_non_closing_join_chunk_cnt); - } - - for(const JoinSource &J : src->closing_joins()) - { - join_ordering.add_join(J, out_values.m_closing_join_chunk_cnt); - } - - for(const CapSource &C : src->caps()) - { - cap_ordering.add_cap(C, out_values.m_cap_chunk_cnt); - } } m_non_closing_edges.m_vertex_data_range.m_end = out_values.m_non_closing_edge_vertex_cnt; @@ -2038,19 +1106,8 @@ StrokedPathSubset(CreationValues &out_values, m_non_closing_edges.m_chunk = out_values.m_non_closing_edge_chunk_cnt; m_closing_edges.m_chunk = out_values.m_closing_edge_chunk_cnt; - m_non_closing_joins.m_elements.m_end = join_ordering.non_closing_edge().size(); - m_closing_joins.m_elements.m_end = join_ordering.closing_edge().size(); - m_caps.m_elements.m_end = cap_ordering.caps().size(); - - m_non_closing_joins.m_chunk = out_values.m_non_closing_join_chunk_cnt; - m_closing_joins.m_chunk = out_values.m_closing_join_chunk_cnt; - m_caps.m_chunk = out_values.m_cap_chunk_cnt; - ++out_values.m_non_closing_edge_chunk_cnt; ++out_values.m_closing_edge_chunk_cnt; - ++out_values.m_non_closing_join_chunk_cnt; - ++out_values.m_closing_join_chunk_cnt; - ++out_values.m_cap_chunk_cnt; } void @@ -2083,7 +1140,6 @@ compute_chunks(bool include_closing_edge, float item_space_additional_room, unsigned int max_attribute_cnt, unsigned int max_index_cnt, - bool take_joins_outside_of_region, ChunkSetPrivate &dst) { scratch.m_adjusted_clip_eqs.resize(clip_equations.size()); @@ -2106,15 +1162,6 @@ compute_chunks(bool include_closing_edge, } dst.reset(); - if (take_joins_outside_of_region) - { - dst.add_join_chunk(m_non_closing_joins); - if (include_closing_edge) - { - dst.add_join_chunk(m_closing_joins); - } - dst.ignore_join_adds(); - } compute_chunks_implement(include_closing_edge, scratch, item_space_additional_room, max_attribute_cnt, max_index_cnt, dst); @@ -2136,16 +1183,9 @@ compute_chunks_take_all(bool include_closing_edge, && (!include_closing_edge || m_closing_edges.chunk_fits(max_attribute_cnt, max_index_cnt))) { dst.add_edge_chunk(m_non_closing_edges); - dst.add_join_chunk(m_non_closing_joins); - if (include_closing_edge) { dst.add_edge_chunk(m_closing_edges); - dst.add_join_chunk(m_closing_joins); - } - else - { - dst.add_cap_chunk(m_caps); } } else if (have_children()) @@ -2178,8 +1218,7 @@ compute_chunks_implement(bool include_closing_edge, return; } - /* clip the bounding box of this StrokedPathSubset - */ + /* clip the bounding box of this StrokedPathSubset */ vecN bb; bool unclipped; @@ -2218,17 +1257,11 @@ compute_chunks_implement(bool include_closing_edge, { FASTUIDRAWassert(m_non_closing_edges.chunk_fits(max_attribute_cnt, max_index_cnt)); dst.add_edge_chunk(m_non_closing_edges); - dst.add_join_chunk(m_non_closing_joins); if (include_closing_edge) { FASTUIDRAWassert(m_closing_edges.chunk_fits(max_attribute_cnt, max_index_cnt)); dst.add_edge_chunk(m_closing_edges); - dst.add_join_chunk(m_closing_joins); - } - else - { - dst.add_cap_chunk(m_caps); } } } @@ -2467,1441 +1500,120 @@ process_sub_edge(const SingleSubEdge &sub_edge, unsigned int depth, vert_offset += StrokedPathSubset::points_per_segment; } - -////////////////////////////////////////////// -// JoinCount methods -JoinCount:: -JoinCount(const ContourData &P): - m_number_close_joins(0), - m_number_non_close_joins(0) +///////////////////////////////////////////// +// StrokedPathPrivate methods +StrokedPathPrivate:: +StrokedPathPrivate(const fastuidraw::TessellatedPath &P, + const fastuidraw::StrokedCapsJoins::Builder &b): + m_caps_joins(b), + m_subset(nullptr) { - for(unsigned int o = 0; o < P.number_contours(); ++o) + if (!P.point_data().empty()) { - if (P.number_edges(o) >= 2) - { - m_number_non_close_joins += P.number_edges(o) - 2; - m_number_close_joins += 2; - } + m_empty_path = false; + create_edges(P); + } + else + { + m_empty_path = true; + std::fill(m_chunk_of_edges.begin(), m_chunk_of_edges.end(), 0); } } -//////////////////////////////////////////////// -// CommonJoinData methods -CommonJoinData:: -CommonJoinData(const fastuidraw::vec2 &p0, - const fastuidraw::vec2 &n0, - const fastuidraw::vec2 &p1, - const fastuidraw::vec2 &n1, - float distance_from_edge_start, - float distance_from_contour_start, - float edge_length, - float open_contour_length, - float closed_contour_length): - m_distance_from_edge_start(distance_from_edge_start), - m_distance_from_contour_start(distance_from_contour_start), - m_edge_length(edge_length), - m_open_contour_length(open_contour_length), - m_closed_contour_length(closed_contour_length) -{ - /* Explanation: - * We have two curves, a(t) and b(t) with a(1) = b(0) - * The point p0 represents the end of a(t) and the - * point p1 represents the start of b(t). - * - * When stroking we have four auxiliary curves: - * a0(t) = a(t) + w * a_n(t) - * a1(t) = a(t) - w * a_n(t) - * b0(t) = b(t) + w * b_n(t) - * b1(t) = b(t) - w * b_n(t) - * where - * w = width of stroking - * a_n(t) = J( a'(t) ) / || a'(t) || - * b_n(t) = J( b'(t) ) / || b'(t) || - * when - * J(x, y) = (-y, x). - * - * A Bevel join is a triangle that connects - * consists of p, A and B where p is a(1)=b(0), - * A is one of a0(1) or a1(1) and B is one - * of b0(0) or b1(0). Now if we use a0(1) for - * A then we will use b0(0) for B because - * the normals are generated the same way for - * a(t) and b(t). Then, the questions comes - * down to, do we wish to add or subtract the - * normal. That value is represented by m_lambda. - * - * Now to figure out m_lambda. Let q0 be a point - * on a(t) before p=a(1). The q0 is given by - * - * q0 = p - s * m_v0 - * - * and let q1 be a point on b(t) after p=b(0), - * - * q1 = p + t * m_v1 - * - * where both s, t are positive. Let - * - * z = (q0+q1) / 2 - * - * the point z is then on the side of the join - * of the acute angle of the join. - * - * With this in mind, if either of - * or is positive then we want - * to add by -w * n rather than w * n. - * - * Note that: - * - * = 0.5 * < -s * m_v0 + t * m_v1, m_n1 > - * = -0.5 * s * + 0.5 * t * - * = -0.5 * s * - * = -0.5 * s * - * - * and - * - * = 0.5 * < -s * m_v0 + t * m_v1, m_n0 > - * = -0.5 * s * + 0.5 * t * - * = 0.5 * t * - * = 0.5 * t * - * = -0.5 * t * - * - * (the last line because transpose(J) = -J). Notice - * that the sign of and the sign of - * is then the same. - * - * thus m_lambda is positive if is negative. - */ - m_p0 = p0; - m_n0 = n0; - m_v0 = fastuidraw::vec2(m_n0.y(), -m_n0.x()); - - m_p1 = p1; - m_n1 = n1; - m_v1 = fastuidraw::vec2(m_n1.y(), -m_n1.x()); - - m_det = fastuidraw::dot(m_v1, m_n0); - if (m_det > 0.0f) - { - m_lambda = -1.0f; - } - else - { - m_lambda = 1.0f; - } -} - -float -CommonJoinData:: -compute_lambda(const fastuidraw::vec2 &n0, const fastuidraw::vec2 &n1) +StrokedPathPrivate:: +~StrokedPathPrivate() { - fastuidraw::vec2 v1; - float d; - - v1 = fastuidraw::vec2(n1.y(), -n1.x()); - d = fastuidraw::dot(v1, n0); - if (d > 0.0f) - { - return -1.0f; - } - else + if (!m_empty_path) { - return 1.0f; + FASTUIDRAWdelete(m_subset); } } -///////////////////////////////////////////////// -// JoinCreatorBase methods -JoinCreatorBase:: -JoinCreatorBase(const PathData &P, - const StrokedPathSubset *st): - m_P(P.m_contour_data), - m_ordering(P.m_join_ordering), - m_st(st), - m_num_verts(0), - m_num_indices(0), - m_num_chunks(P.m_number_join_chunks), - m_num_joins(0), - m_post_ctor_initalized_called(false) -{} - void -JoinCreatorBase:: -post_ctor_initalize(void) +StrokedPathPrivate:: +ready_builder(const fastuidraw::TessellatedPath *tess, + fastuidraw::StrokedCapsJoins::Builder &b) { - FASTUIDRAWassert(!m_post_ctor_initalized_called); - m_post_ctor_initalized_called = true; - - for(const JoinSource &J : m_ordering.non_closing_edge()) + for(unsigned int c = 0; c < tess->number_contours(); ++c) { - add_join(m_num_joins, - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join), - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join + 1), - m_num_verts, m_num_indices); - ++m_num_joins; - } - - for(const JoinSource &J : m_ordering.closing_edge()) - { - add_join(m_num_joins, - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join), - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join + 1), - m_num_verts, m_num_indices); - ++m_num_joins; + ready_builder_contour(tess, c, b); } } void -JoinCreatorBase:: -compute_sizes(unsigned int &num_attributes, - unsigned int &num_indices, - unsigned int &num_attribute_chunks, - unsigned int &num_index_chunks, - unsigned int &number_z_ranges) const -{ - FASTUIDRAWassert(m_post_ctor_initalized_called); - num_attributes = m_num_verts; - num_indices = m_num_indices; - number_z_ranges = num_attribute_chunks = num_index_chunks = m_num_chunks; -} - -void -JoinCreatorBase:: -fill_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int chunk, unsigned int depth, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges) const -{ - unsigned int v(vertex_offset), i(index_offset); - - FASTUIDRAWassert(join_id < m_num_joins); - - fill_join_implement(join_id, into_join, leaving_join, - pts, depth, indices, vertex_offset, index_offset); - - join_vertex_ranges[join_id].m_begin = v; - join_vertex_ranges[join_id].m_end = vertex_offset; - - join_index_ranges[join_id].m_begin = i; - join_index_ranges[join_id].m_end = index_offset; - - attribute_chunks[chunk] = pts.sub_array(v, vertex_offset - v); - index_chunks[chunk] = indices.sub_array(i, index_offset - i); - index_adjusts[chunk] = -int(v); - zranges[chunk] = fastuidraw::range_type(depth, depth + 1); -} - -void -JoinCreatorBase:: -fill_data(fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) const +StrokedPathPrivate:: +ready_builder_contour(const fastuidraw::TessellatedPath *tess, + unsigned int c, + fastuidraw::StrokedCapsJoins::Builder &b) { - unsigned int vertex_offset(0), index_offset(0), join_id(0); - std::vector > jvr(m_num_joins), jir(m_num_joins); - fastuidraw::c_array > join_vertex_ranges, join_index_ranges; - - join_vertex_ranges = fastuidraw::make_c_array(jvr); - join_index_ranges = fastuidraw::make_c_array(jir); - - FASTUIDRAWassert(attribute_data.size() == m_num_verts); - FASTUIDRAWassert(index_data.size() == m_num_indices); - FASTUIDRAWassert(attribute_chunks.size() == m_num_chunks); - FASTUIDRAWassert(index_chunks.size() == m_num_chunks); - FASTUIDRAWassert(zranges.size() == m_num_chunks); - FASTUIDRAWassert(index_adjusts.size() == m_num_chunks); - - /* Note that we reverse the the depth value, we need to do this because - * we want the joins draw first to obscure the joins drawn later. - */ - for(const OrderingEntry &J : m_ordering.non_closing_edge()) - { - fill_join(join_id, - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join), - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join + 1), - J.m_chunk, J.m_depth, - attribute_data, index_data, - vertex_offset, index_offset, - attribute_chunks, index_chunks, - zranges, index_adjusts, - join_vertex_ranges, - join_index_ranges); - ++join_id; - } + fastuidraw::c_array last_pts; + fastuidraw::vec2 delta, last_normal; + float delta_mag; + const float tol(0.000001f); - for(const OrderingEntry &J : m_ordering.closing_edge()) - { - fill_join(join_id, - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join), - m_P.m_per_contour_data[J.m_contour].edge_data(J.m_edge_going_into_join + 1), - J.m_chunk, J.m_depth, - attribute_data, index_data, - vertex_offset, index_offset, - attribute_chunks, index_chunks, - zranges, index_adjusts, - join_vertex_ranges, - join_index_ranges); - ++join_id; - } + last_pts = tess->edge_point_data(c, 0); - FASTUIDRAWassert(vertex_offset == m_num_verts); - FASTUIDRAWassert(index_offset == m_num_indices); - set_chunks(m_st, - join_vertex_ranges, join_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); -} - -void -JoinCreatorBase:: -set_chunks(const StrokedPathSubset *st, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) -{ - process_chunk(st->non_closing_joins(), - join_vertex_ranges, join_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - - process_chunk(st->closing_joins(), - join_vertex_ranges, join_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - - if (st->have_children()) + delta = last_pts[1].m_p - last_pts[0].m_p; + delta_mag = delta.magnitude(); + if (delta_mag < tol) { - set_chunks(st->child(0), - join_vertex_ranges, join_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - - set_chunks(st->child(1), - join_vertex_ranges, join_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - } -} - -void -JoinCreatorBase:: -process_chunk(const RangeAndChunk &ch, - fastuidraw::c_array > join_vertex_ranges, - fastuidraw::c_array > join_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) -{ - unsigned int K; - fastuidraw::range_type vr, ir; - - if (ch.m_elements.m_begin < ch.m_elements.m_end) - { - vr.m_begin = join_vertex_ranges[ch.m_elements.m_begin].m_begin; - vr.m_end = join_vertex_ranges[ch.m_elements.m_end - 1].m_end; - - ir.m_begin = join_index_ranges[ch.m_elements.m_begin].m_begin; - ir.m_end = join_index_ranges[ch.m_elements.m_end - 1].m_end; + delta = fastuidraw::vec2(1.0f, 0.0f); } else { - vr.m_begin = vr.m_end = 0; - ir.m_begin = ir.m_end = 0; + delta /= delta_mag; } + last_normal = delta; + b.begin_contour(last_pts[0].m_p, delta); - K = ch.m_chunk; - attribute_chunks[K] = attribute_data.sub_array(vr); - index_chunks[K] = index_data.sub_array(ir); - zranges[K] = fastuidraw::range_type(ch.m_depth_range.m_begin, ch.m_depth_range.m_end); - index_adjusts[K] = -int(vr.m_begin); -} - -///////////////////////////////////////////////// -// RoundedJoinCreator::PerJoinData methods -RoundedJoinCreator::PerJoinData:: -PerJoinData(const fastuidraw::TessellatedPath::point &p0, - const fastuidraw::TessellatedPath::point &p1, - const fastuidraw::vec2 &n0_from_stroking, - const fastuidraw::vec2 &n1_from_stroking, - float thresh): - CommonJoinData(p0.m_p, n0_from_stroking, p1.m_p, n1_from_stroking, - p0.m_distance_from_edge_start, p0.m_distance_from_contour_start, - p0.m_edge_length, p0.m_open_contour_length, p0.m_closed_contour_length) -{ - /* n0z represents the start point of the rounded join in the complex plane - * as if the join was at the origin, n1z represents the end point of the - * rounded join in the complex plane as if the join was at the origin. - */ - std::complex n0z(m_lambda * m_n0.x(), m_lambda * m_n0.y()); - std::complex n1z(m_lambda * m_n1.x(), m_lambda * m_n1.y()); - - /* n1z_times_conj_n0z satisfies: - * n1z = n1z_times_conj_n0z * n0z - * i.e. it represents the arc-movement from n0z to n1z - */ - std::complex n1z_times_conj_n0z(n1z * std::conj(n0z)); - - m_arc_start = n0z; - m_delta_theta = std::atan2(n1z_times_conj_n0z.imag(), n1z_times_conj_n0z.real()); - m_num_arc_points = fastuidraw::detail::number_segments_for_tessellation(m_delta_theta, thresh); - m_delta_theta /= static_cast(m_num_arc_points - 1); -} - -void -RoundedJoinCreator::PerJoinData:: -add_data(unsigned int depth, - fastuidraw::c_array pts, - unsigned int &vertex_offset, - fastuidraw::c_array indices, - unsigned int &index_offset) const -{ - unsigned int i, first; - float theta; - fastuidraw::StrokedPoint pt; - - first = vertex_offset; - - pt.m_position = m_p0; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = m_distance_from_edge_start; - pt.m_distance_from_contour_start = m_distance_from_contour_start; - pt.m_edge_length = m_edge_length; - pt.m_open_contour_length = m_open_contour_length; - pt.m_closed_contour_length = m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = m_p0; - pt.m_pre_offset = m_lambda * m_n0; - pt.m_distance_from_edge_start = m_distance_from_edge_start; - pt.m_distance_from_contour_start = m_distance_from_contour_start; - pt.m_edge_length = m_edge_length; - pt.m_open_contour_length = m_open_contour_length; - pt.m_closed_contour_length = m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - for(i = 1, theta = m_delta_theta; i < m_num_arc_points - 1; ++i, theta += m_delta_theta, ++vertex_offset) + for(unsigned int e = 1, ende = tess->number_edges(c); e < ende; ++e) { - float t, c, s; - std::complex cs_as_complex; - - t = static_cast(i) / static_cast(m_num_arc_points - 1); - c = std::cos(theta); - s = std::sin(theta); - cs_as_complex = std::complex(c, s) * m_arc_start; - - pt.m_position = m_p0; - pt.m_pre_offset = m_lambda * fastuidraw::vec2(m_n0.x(), m_n1.x()); - pt.m_auxiliary_offset = fastuidraw::vec2(t, cs_as_complex.real()); - pt.m_distance_from_edge_start = m_distance_from_edge_start; - pt.m_distance_from_contour_start = m_distance_from_contour_start; - pt.m_edge_length = m_edge_length; - pt.m_open_contour_length = m_open_contour_length; - pt.m_closed_contour_length = m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_rounded_join, depth); - - if (m_lambda * m_n0.y() < 0.0f) + fastuidraw::c_array pts; + fastuidraw::vec2 delta_into, delta_leaving; + float mag; + + pts = tess->edge_point_data(c, e); + delta_into = last_pts[last_pts.size() - 1].m_p - last_pts[last_pts.size() - 2].m_p; + mag = delta_into.magnitude(); + if (mag < tol) { - pt.m_packed_data |= fastuidraw::StrokedPoint::normal0_y_sign_mask; + delta_into = last_normal; } - - if (m_lambda * m_n1.y() < 0.0f) + else { - pt.m_packed_data |= fastuidraw::StrokedPoint::normal1_y_sign_mask; + delta_into /= mag; + last_normal = delta_into; } - if (cs_as_complex.imag() < 0.0f) + delta_leaving = pts[1].m_p - pts[0].m_p; + mag = delta_leaving.magnitude(); + if (mag < tol) { - pt.m_packed_data |= fastuidraw::StrokedPoint::sin_sign_mask; + delta_leaving = last_normal; + } + else + { + delta_leaving /= mag; + last_normal = delta_leaving; } - pt.pack_point(&pts[vertex_offset]); - } - - pt.m_position = m_p1; - pt.m_pre_offset = m_lambda * m_n1; - pt.m_distance_from_edge_start = m_distance_from_edge_start; - pt.m_distance_from_contour_start = m_distance_from_contour_start; - pt.m_edge_length = m_edge_length; - pt.m_open_contour_length = m_open_contour_length; - pt.m_closed_contour_length = m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - -/////////////////////////////////////////////////// -// RoundedJoinCreator methods -RoundedJoinCreator:: -RoundedJoinCreator(const PathData &P, - const StrokedPathSubset *st, - float thresh): - JoinCreatorBase(P, st), - m_thresh(thresh) -{ - JoinCount J(P.m_contour_data); - m_per_join_data.reserve(J.m_number_close_joins + J.m_number_non_close_joins); - post_ctor_initalize(); -} - -void -RoundedJoinCreator:: -add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const -{ - FASTUIDRAWunused(join_id); - PerJoinData J(into_join.m_end_pt, leaving_join.m_start_pt, - into_join.m_end_normal, leaving_join.m_begin_normal, - m_thresh); - - m_per_join_data.push_back(J); - - /* a triangle fan centered at p0 = p1 with - * m_num_arc_points along an edge - */ - vert_count += (1 + J.m_num_arc_points); - index_count += 3 * (J.m_num_arc_points - 1); -} - - -void -RoundedJoinCreator:: -fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const -{ - FASTUIDRAWunused(into_join); - FASTUIDRAWunused(leaving_join); - FASTUIDRAWassert(join_id < m_per_join_data.size()); - m_per_join_data[join_id].add_data(depth, pts, vertex_offset, indices, index_offset); -} - -/////////////////////////////////////////////////// -// BevelJoinCreator methods -BevelJoinCreator:: -BevelJoinCreator(const PathData &P, - const StrokedPathSubset *st): - JoinCreatorBase(P, st) -{ - post_ctor_initalize(); -} - -void -BevelJoinCreator:: -add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const -{ - FASTUIDRAWunused(join_id); - - /* one triangle per bevel join - */ - vert_count += 3; - index_count += 3; - - m_n0.push_back(into_join.m_end_normal); - m_n1.push_back(leaving_join.m_begin_normal); -} - -void -BevelJoinCreator:: -fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const -{ - const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); - const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPoint pt; - - CommonJoinData J(prev_pt.m_p, m_n0[join_id], - next_pt.m_p, m_n1[join_id], - prev_pt.m_distance_from_edge_start, - prev_pt.m_distance_from_contour_start, - //using p0 to decide the edge length, as - //we think of the join as ending an edge. - prev_pt.m_edge_length, - prev_pt.m_open_contour_length, - prev_pt.m_closed_contour_length); - - pt.m_position = J.m_p0; - pt.m_pre_offset = J.m_lambda * J.m_n0; - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset + 0]); - - pt.m_position = J.m_p0; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset + 1]); - - pt.m_position = J.m_p1; - pt.m_pre_offset = J.m_lambda * J.m_n1; - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset + 2]); - - add_triangle_fan(vertex_offset, vertex_offset + 3, indices, index_offset); - - vertex_offset += 3; -} - -/////////////////////////////////////////////////// -// MiterClipJoinCreator methods -MiterClipJoinCreator:: -MiterClipJoinCreator(const PathData &P, - const StrokedPathSubset *st): - JoinCreatorBase(P, st) -{ - post_ctor_initalize(); -} - -void -MiterClipJoinCreator:: -add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const -{ - FASTUIDRAWunused(join_id); - /* Each join is a triangle fan from 5 points - * (thus 3 triangles, which is 9 indices) - */ - vert_count += 5; - index_count += 9; - - m_n0.push_back(into_join.m_end_normal); - m_n1.push_back(leaving_join.m_begin_normal); -} - - -void -MiterClipJoinCreator:: -fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const -{ - FASTUIDRAWunused(join_id); - - const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); - const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPoint pt; - unsigned int first; - - CommonJoinData J(prev_pt.m_p, m_n0[join_id], - next_pt.m_p, m_n1[join_id], - prev_pt.m_distance_from_edge_start, - prev_pt.m_distance_from_contour_start, - //using p0 to decide the edge length, as - //we think of the join as ending an edge. - prev_pt.m_edge_length, - prev_pt.m_open_contour_length, - prev_pt.m_closed_contour_length); - - /* The miter point is given by where the two boundary - * curves intersect. The two curves are given by: - * - * a(t) = J.m_p0 + stroke_width * J.m_lamba * J.m_n0 + t * J.m_v0 - * b(s) = J.m_p1 + stroke_width * J.m_lamba * J.m_n1 - s * J.m_v1 - * - * With J.m_p0 is the same value as J.m_p1, the location - * of the join. - * - * We need to solve a(t) = b(s) and compute that location. - * Linear algebra gives us that: - * - * t = - stroke_width * J.m_lamba * r - * s = - stroke_width * J.m_lamba * r - * where - * r = ( - 1) / - * - * thus - * - * a(t) = J.m_p0 + stroke_width * ( J.m_lamba * J.m_n0 - r * J.m_lamba * J.m_v0) - * = b(s) - * = J.m_p1 + stroke_width * ( J.m_lamba * J.m_n1 + r * J.m_lamba * J.m_v1) - */ - - first = vertex_offset; - - // join center point. - pt.m_position = J.m_p0; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // join point from curve into join - pt.m_position = J.m_p0; - pt.m_pre_offset = J.m_lambda * J.m_n0; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // miter point A - pt.m_position = J.m_p0; - pt.m_pre_offset = J.m_n0; - pt.m_auxiliary_offset = J.m_n1; - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // miter point B - pt.m_position = J.m_p1; - pt.m_pre_offset = J.m_n1; - pt.m_auxiliary_offset = J.m_n0; - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join_lambda_negated, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // join point from curve out from join - pt.m_position = J.m_p1; - pt.m_pre_offset = J.m_lambda * J.m_n1; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - -//////////////////////////////////// -// MiterJoinCreator methods -template -MiterJoinCreator:: -MiterJoinCreator(const PathData &P, - const StrokedPathSubset *st): - JoinCreatorBase(P, st) -{ - post_ctor_initalize(); -} - -template -void -MiterJoinCreator:: -add_join(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - unsigned int &vert_count, unsigned int &index_count) const -{ - /* Each join is a triangle fan from 4 points - * (thus 2 triangles, which is 6 indices) - */ - FASTUIDRAWunused(join_id); - - vert_count += 4; - index_count += 6; - - m_n0.push_back(into_join.m_end_normal); - m_n1.push_back(leaving_join.m_begin_normal); -} - -template -void -MiterJoinCreator:: -fill_join_implement(unsigned int join_id, - const PerEdgeData &into_join, - const PerEdgeData &leaving_join, - fastuidraw::c_array pts, - unsigned int depth, - fastuidraw::c_array indices, - unsigned int &vertex_offset, unsigned int &index_offset) const -{ - FASTUIDRAWunused(join_id); - - const fastuidraw::TessellatedPath::point &prev_pt(into_join.m_end_pt); - const fastuidraw::TessellatedPath::point &next_pt(leaving_join.m_start_pt); - fastuidraw::StrokedPoint pt; - unsigned int first; - - CommonJoinData J(prev_pt.m_p, m_n0[join_id], - next_pt.m_p, m_n1[join_id], - prev_pt.m_distance_from_edge_start, - prev_pt.m_distance_from_contour_start, - //using p0 to decide the edge length, as - //we think of the join as ending an edge. - prev_pt.m_edge_length, - prev_pt.m_open_contour_length, - prev_pt.m_closed_contour_length); - - /* The miter point is given by where the two boundary - * curves intersect. The two curves are given by: - * - * a(t) = J.m_p0 + stroke_width * J.m_lamba * J.m_n0 + t * J.m_v0 - * b(s) = J.m_p1 + stroke_width * J.m_lamba * J.m_n1 - s * J.m_v1 - * - * With J.m_p0 is the same value as J.m_p1, the location - * of the join. - * - * We need to solve a(t) = b(s) and compute that location. - * Linear algebra gives us that: - * - * t = - stroke_width * J.m_lamba * r - * s = - stroke_width * J.m_lamba * r - * where - * r = ( - 1) / - * - * thus - * - * a(t) = J.m_p0 + stroke_width * ( J.m_lamba * J.m_n0 - r * J.m_lamba * J.m_v0) - * = b(s) - * = J.m_p1 + stroke_width * ( J.m_lamba * J.m_n1 + r * J.m_lamba * J.m_v1) - */ - - first = vertex_offset; - - // join center point. - pt.m_position = J.m_p0; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // join point from curve into join - pt.m_position = J.m_p0; - pt.m_pre_offset = J.m_lambda * J.m_n0; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // miter point - pt.m_position = J.m_p0; - pt.m_pre_offset = J.m_n0; - pt.m_auxiliary_offset = J.m_n1; - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, tp, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - // join point from curve out from join - pt.m_position = J.m_p1; - pt.m_pre_offset = J.m_lambda * J.m_n1; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = J.m_distance_from_edge_start; - pt.m_distance_from_contour_start = J.m_distance_from_contour_start; - pt.m_edge_length = J.m_edge_length; - pt.m_open_contour_length = J.m_open_contour_length; - pt.m_closed_contour_length = J.m_closed_contour_length; - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - -/////////////////////////////////////////////// -// CapCreatorBase methods -CapCreatorBase:: -CapCreatorBase(const PathData &P, - const StrokedPathSubset *st, - PointIndexCapSize sz): - m_P(P.m_contour_data), - m_ordering(P.m_cap_ordering), - m_st(st), - m_num_chunks(P.m_number_cap_chunks), - m_size(sz) -{ -} - -void -CapCreatorBase:: -compute_sizes(unsigned int &num_attributes, - unsigned int &num_indices, - unsigned int &num_attribute_chunks, - unsigned int &num_index_chunks, - unsigned int &number_z_ranges) const -{ - num_attributes = m_size.m_verts; - num_indices = m_size.m_indices; - number_z_ranges = num_attribute_chunks = num_index_chunks = m_num_chunks; -} - -void -CapCreatorBase:: -fill_data(fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) const -{ - unsigned int vertex_offset(0u), index_offset(0u), cap_id(0u); - std::vector > cvr(m_num_chunks), cir(m_num_chunks); - - for(const OrderingEntry C : m_ordering.caps()) - { - unsigned int v(vertex_offset), i(index_offset); - const fastuidraw::vec2 *normal; - const fastuidraw::TessellatedPath::point *pt; - - normal = C.m_is_start_cap ? - &m_P.m_per_contour_data[C.m_contour].m_begin_cap_normal: - &m_P.m_per_contour_data[C.m_contour].m_end_cap_normal; - - pt = C.m_is_start_cap ? - &m_P.m_per_contour_data[C.m_contour].m_start_contour_pt: - &m_P.m_per_contour_data[C.m_contour].m_end_contour_pt; - - add_cap(*normal, C.m_is_start_cap, C.m_depth, *pt, - attribute_data, index_data, vertex_offset, index_offset); - - cvr[cap_id].m_begin = v; - cvr[cap_id].m_end = vertex_offset; - - cir[cap_id].m_begin = i; - cir[cap_id].m_end = index_offset; - - attribute_chunks[C.m_chunk] = attribute_data.sub_array(cvr[cap_id]); - index_chunks[C.m_chunk] = index_data.sub_array(cir[cap_id]); - zranges[C.m_chunk] = fastuidraw::range_type(C.m_depth, C.m_depth + 1); - index_adjusts[C.m_chunk] = -int(v); - - ++cap_id; - } - - FASTUIDRAWassert(vertex_offset == m_size.m_verts); - FASTUIDRAWassert(index_offset == m_size.m_indices); - - set_chunks(m_st, - fastuidraw::make_c_array(cvr), - fastuidraw::make_c_array(cir), - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); -} - -void -CapCreatorBase:: -set_chunks(const StrokedPathSubset *st, - fastuidraw::c_array > cap_vertex_ranges, - fastuidraw::c_array > cap_index_ranges, - fastuidraw::c_array attribute_data, - fastuidraw::c_array index_data, - fastuidraw::c_array > attribute_chunks, - fastuidraw::c_array > index_chunks, - fastuidraw::c_array > zranges, - fastuidraw::c_array index_adjusts) -{ - const RangeAndChunk &ch(st->caps()); - fastuidraw::range_type vr, ir; - unsigned int K; - - if (ch.m_elements.m_begin < ch.m_elements.m_end) - { - vr.m_begin = cap_vertex_ranges[ch.m_elements.m_begin].m_begin; - vr.m_end = cap_vertex_ranges[ch.m_elements.m_end - 1].m_end; - - ir.m_begin = cap_index_ranges[ch.m_elements.m_begin].m_begin; - ir.m_end = cap_index_ranges[ch.m_elements.m_end - 1].m_end; - - FASTUIDRAWassert(ch.m_depth_range.m_begin < ch.m_depth_range.m_end); - } - else - { - vr.m_begin = vr.m_end = 0; - ir.m_begin = ir.m_end = 0; - FASTUIDRAWassert(ch.m_depth_range.m_begin == ch.m_depth_range.m_end); - } - - K = ch.m_chunk; - attribute_chunks[K] = attribute_data.sub_array(vr); - index_chunks[K] = index_data.sub_array(ir); - zranges[K] = fastuidraw::range_type(ch.m_depth_range.m_begin, ch.m_depth_range.m_end); - index_adjusts[K] = -int(vr.m_begin); - - if (st->have_children()) - { - set_chunks(st->child(0), - cap_vertex_ranges, cap_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - - set_chunks(st->child(1), - cap_vertex_ranges, cap_index_ranges, - attribute_data, index_data, - attribute_chunks, index_chunks, - zranges, index_adjusts); - } -} - -/////////////////////////////////////////////////// -// RoundedCapCreator methods -RoundedCapCreator:: -RoundedCapCreator(const PathData &P, - const StrokedPathSubset *st, - float thresh): - CapCreatorBase(P, st, compute_size(P.m_contour_data, thresh)) -{ - m_num_arc_points_per_cap = fastuidraw::detail::number_segments_for_tessellation(M_PI, thresh); - m_delta_theta = static_cast(M_PI) / static_cast(m_num_arc_points_per_cap - 1); -} - -PointIndexCapSize -RoundedCapCreator:: -compute_size(const ContourData &P, float thresh) -{ - unsigned int num_caps, num_arc_points_per_cap; - PointIndexCapSize return_value; - - num_arc_points_per_cap = fastuidraw::detail::number_segments_for_tessellation(M_PI, thresh); - - /* each cap is a triangle fan centered at the cap point. - */ - num_caps = 2 * P.number_contours(); - return_value.m_verts = (1 + num_arc_points_per_cap) * num_caps; - return_value.m_indices = 3 * (num_arc_points_per_cap - 1) * num_caps; - - return return_value; -} -void -RoundedCapCreator:: -add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const -{ - CommonCapData C(is_starting_cap, p.m_p, normal_from_stroking); - unsigned int first, i; - float theta; - fastuidraw::StrokedPoint pt; - - first = vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - for(i = 1, theta = m_delta_theta; i < m_num_arc_points_per_cap - 1; ++i, theta += m_delta_theta, ++vertex_offset) - { - float s, c; - - s = std::sin(theta); - c = std::cos(theta); - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_auxiliary_offset = fastuidraw::vec2(s, c); - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_rounded_cap, depth); - pt.pack_point(&pts[vertex_offset]); + b.add_join(pts[0].m_p, + last_pts.back().m_edge_length, + delta_into, delta_leaving); + last_pts = pts; } - pt.m_position = C.m_p; - pt.m_pre_offset = -C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - - -/////////////////////////////////////////////////// -// SquareCapCreator methods -PointIndexCapSize -SquareCapCreator:: -compute_size(const ContourData &P) -{ - PointIndexCapSize return_value; - unsigned int num_caps; - - /* each square cap generates 5 new points - * and 3 triangles (= 9 indices) - */ - num_caps = 2 * P.number_contours(); - return_value.m_verts = 5 * num_caps; - return_value.m_indices = 9 * num_caps; - - return return_value; -} - -void -SquareCapCreator:: -add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const -{ - CommonCapData C(is_starting_cap, p.m_p, normal_from_stroking); - unsigned int first; - fastuidraw::StrokedPoint pt; - - first = vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(0, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = C.m_v; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = -C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = C.m_v; - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_square_cap, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = -C.m_n; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_auxiliary_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_packed_data = pack_data(1, fastuidraw::StrokedPoint::offset_shared_with_edge, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - -////////////////////////////////////// -// AdjustableCapCreator methods -PointIndexCapSize -AdjustableCapCreator:: -compute_size(const ContourData &P) -{ - PointIndexCapSize return_value; - unsigned int num_caps; - - num_caps = 2 * P.number_contours(); - return_value.m_verts = number_points_per_fan * num_caps; - return_value.m_indices = number_indices_per_fan * num_caps; - - return return_value; -} - -void -AdjustableCapCreator:: -pack_fan(bool entering_contour, - enum fastuidraw::StrokedPoint::offset_type_t type, - const fastuidraw::TessellatedPath::point &p, - const fastuidraw::vec2 &stroking_normal, - unsigned int depth, - fastuidraw::c_array pts, - unsigned int &vertex_offset, - fastuidraw::c_array indices, - unsigned int &index_offset) -{ - CommonCapData C(entering_contour, p.m_p, stroking_normal); - unsigned int first(vertex_offset); - fastuidraw::StrokedPoint pt; - - pt.m_position = C.m_p; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(0, type, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = C.m_n; - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = fastuidraw::vec2(0.0f, 0.0f); - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(0, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = -C.m_n; - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth) | fastuidraw::StrokedPoint::adjustable_cap_ending_mask; - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - pt.m_position = C.m_p; - pt.m_pre_offset = -C.m_n; - pt.m_auxiliary_offset = C.m_v; - pt.m_distance_from_edge_start = p.m_distance_from_edge_start; - pt.m_distance_from_contour_start = p.m_distance_from_contour_start; - pt.m_edge_length = p.m_edge_length; - pt.m_open_contour_length = p.m_open_contour_length; - pt.m_closed_contour_length = p.m_closed_contour_length; - pt.m_packed_data = pack_data(1, type, depth); - pt.pack_point(&pts[vertex_offset]); - ++vertex_offset; - - add_triangle_fan(first, vertex_offset, indices, index_offset); -} - -void -AdjustableCapCreator:: -add_cap(const fastuidraw::vec2 &normal_from_stroking, - bool is_starting_cap, unsigned int depth, - const fastuidraw::TessellatedPath::point &p0, - fastuidraw::c_array pts, - fastuidraw::c_array indices, - unsigned int &vertex_offset, - unsigned int &index_offset) const -{ - enum fastuidraw::StrokedPoint::offset_type_t tp; - tp = (is_starting_cap) ? - fastuidraw::StrokedPoint::offset_adjustable_cap_contour_start : - fastuidraw::StrokedPoint::offset_adjustable_cap_contour_end; - - pack_fan(is_starting_cap, tp, - p0, normal_from_stroking, depth, - pts, vertex_offset, indices, index_offset); -} - -///////////////////////////////////////////// -// StrokedPathPrivate methods -StrokedPathPrivate:: -StrokedPathPrivate(const fastuidraw::TessellatedPath &P): - m_subset(nullptr) -{ - if (!P.point_data().empty()) + delta = last_pts[last_pts.size() - 1].m_p - last_pts[last_pts.size() - 2].m_p; + delta_mag = delta.magnitude(); + if (delta_mag < tol) { - m_empty_path = false; - create_edges(P); + delta = last_normal; } else { - m_empty_path = true; - m_bevel_joins.mark_as_empty(); - m_miter_clip_joins.mark_as_empty(); - m_miter_joins.mark_as_empty(); - m_miter_bevel_joins.mark_as_empty(); - m_square_caps.mark_as_empty(); - m_adjustable_caps.mark_as_empty(); - std::fill(m_chunk_of_joins.begin(), m_chunk_of_joins.end(), 0); - std::fill(m_chunk_of_edges.begin(), m_chunk_of_edges.end(), 0); - m_chunk_of_caps = 0; - } -} - -StrokedPathPrivate:: -~StrokedPathPrivate() -{ - for(unsigned int i = 0, endi = m_rounded_joins.size(); i < endi; ++i) - { - FASTUIDRAWdelete(m_rounded_joins[i].m_data); - } - - for(unsigned int i = 0, endi = m_rounded_caps.size(); i < endi; ++i) - { - FASTUIDRAWdelete(m_rounded_caps[i].m_data); - } - - if (!m_empty_path) - { - FASTUIDRAWdelete(m_subset); + delta /= delta_mag; } + b.end_contour(last_pts.back().m_edge_length, delta); } void @@ -3913,70 +1625,17 @@ create_edges(const fastuidraw::TessellatedPath &P) FASTUIDRAWassert(!m_empty_path); s = SubEdgeCullingHierarchy::create(P, m_path_data.m_contour_data); - m_subset = StrokedPathSubset::create(s, cnts, m_path_data.m_join_ordering, m_path_data.m_cap_ordering); + m_subset = StrokedPathSubset::create(s, cnts); m_edges.set_data(EdgeAttributeFiller(m_subset, P, cnts)); - m_path_data.m_number_join_chunks = cnts.m_non_closing_join_chunk_cnt + cnts.m_closing_join_chunk_cnt; - m_path_data.m_number_cap_chunks = cnts.m_cap_chunk_cnt; - /* the chunks of the root element have the data for everything. */ m_chunk_of_edges[fastuidraw::StrokedPath::all_non_closing] = m_subset->non_closing_edges().m_chunk; - m_chunk_of_joins[fastuidraw::StrokedPath::all_non_closing] = m_subset->non_closing_joins().m_chunk; - m_chunk_of_edges[fastuidraw::StrokedPath::all_closing] = m_subset->closing_edges().m_chunk; - m_chunk_of_joins[fastuidraw::StrokedPath::all_closing] = m_subset->closing_joins().m_chunk; - - m_chunk_of_caps = m_subset->caps().m_chunk; FASTUIDRAWdelete(s); } -template -const fastuidraw::PainterAttributeData& -StrokedPathPrivate:: -fetch_create(float thresh, std::vector &values) -{ - if (values.empty()) - { - fastuidraw::PainterAttributeData *newD; - newD = FASTUIDRAWnew fastuidraw::PainterAttributeData(); - newD->set_data(T(m_path_data, m_subset, 1.0f)); - values.push_back(ThreshWithData(newD, 1.0f)); - } - - /* we set a hard tolerance of 1e-6. Should we - * set it as a ratio of the bounding box of - * the underlying tessellated path? - */ - thresh = fastuidraw::t_max(thresh, float(1e-6)); - if (values.back().m_thresh <= thresh) - { - std::vector::const_iterator iter; - iter = std::lower_bound(values.begin(), values.end(), thresh, - ThreshWithData::reverse_compare_against_thresh); - FASTUIDRAWassert(iter != values.end()); - FASTUIDRAWassert(iter->m_thresh <= thresh); - FASTUIDRAWassert(iter->m_data != nullptr); - return *iter->m_data; - } - else - { - float t; - t = values.back().m_thresh; - while(t > thresh) - { - fastuidraw::PainterAttributeData *newD; - - t *= 0.5f; - newD = FASTUIDRAWnew fastuidraw::PainterAttributeData(); - newD->set_data(T(m_path_data, m_subset, t)); - values.push_back(ThreshWithData(newD, t)); - } - return *values.back().m_data; - } -} - ////////////////////////////////////////////// // fastuidraw::StrokedPath::ScratchSpace methods fastuidraw::StrokedPath::ScratchSpace:: @@ -4006,59 +1665,6 @@ add_edge_chunk(const EdgeRanges &ed) } } -void -ChunkSetPrivate:: -add_join_chunk(const RangeAndChunk &j) -{ - if (j.non_empty() && !m_ignore_join_adds) - { - m_join_chunks.push_back(j.m_chunk); - m_join_ranges.push_back(j.m_elements); - } -} - -void -ChunkSetPrivate:: -add_cap_chunk(const RangeAndChunk &c) -{ - if (c.non_empty()) - { - m_cap_chunks.push_back(c.m_chunk); - } -} - -void -ChunkSetPrivate:: -handle_dashed_evaluator(const fastuidraw::DashEvaluatorBase *dash_evaluator, - const fastuidraw::PainterShaderData::DataBase *dash_data, - const fastuidraw::StrokedPath &path) -{ - if (dash_evaluator != nullptr) - { - const fastuidraw::PainterAttributeData &joins(path.bevel_joins()); - unsigned int cnt(0); - - m_join_chunks.clear(); - for(const fastuidraw::range_type &R : m_join_ranges) - { - for(unsigned int J = R.m_begin; J < R.m_end; ++J, ++cnt) - { - unsigned int chunk; - fastuidraw::c_array attribs; - - chunk = path.join_chunk(J); - attribs = joins.attribute_data_chunk(chunk); - FASTUIDRAWassert(!attribs.empty()); - FASTUIDRAWassert(attribs.size() == 3); - if (dash_evaluator->covered_by_dash_pattern(dash_data, attribs[0])) - { - m_join_chunks.push_back(chunk); - } - } - } - } -} - ////////////////////////////////////////// // fastuidraw::StrokedPath::ChunkSet methods fastuidraw::StrokedPath::ChunkSet:: @@ -4090,7 +1696,7 @@ join_chunks(void) const { ChunkSetPrivate *d; d = static_cast(m_d); - return d->join_chunks(); + return d->m_caps_joins.join_chunks(); } fastuidraw::c_array @@ -4099,16 +1705,17 @@ cap_chunks(void) const { ChunkSetPrivate *d; d = static_cast(m_d); - return d->cap_chunks(); + return d->m_caps_joins.cap_chunks(); } - ////////////////////////////////////////////////////////////// // fastuidraw::StrokedPath methods fastuidraw::StrokedPath:: StrokedPath(const fastuidraw::TessellatedPath &P) { - m_d = FASTUIDRAWnew StrokedPathPrivate(P); + StrokedCapsJoins::Builder b; + StrokedPathPrivate::ready_builder(&P, b); + m_d = FASTUIDRAWnew StrokedPathPrivate(P, b); } fastuidraw::StrokedPath:: @@ -4144,6 +1751,19 @@ compute_chunks(ScratchSpace &scratch_space, scratch_space_ptr = static_cast(scratch_space.m_d); chunk_set_ptr = static_cast(dst.m_d); + d->m_caps_joins.compute_chunks(scratch_space_ptr->m_caps_joins, + dash_evaluator, dash_data, + clip_equations, + clip_matrix_local, + recip_dimensions, + pixels_additional_room, + item_space_additional_room, + include_closing_edges, + max_attribute_cnt, + max_index_cnt, + take_joins_outside_of_region, + chunk_set_ptr->m_caps_joins); + if (d->m_empty_path) { chunk_set_ptr->reset(); @@ -4159,9 +1779,7 @@ compute_chunks(ScratchSpace &scratch_space, item_space_additional_room, max_attribute_cnt, max_index_cnt, - take_joins_outside_of_region, *chunk_set_ptr); - chunk_set_ptr->handle_dashed_evaluator(dash_evaluator, dash_data, *this); } const fastuidraw::PainterAttributeData& @@ -4188,7 +1806,7 @@ number_joins(bool include_joins_of_closing_edge) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_path_data.m_join_ordering.number_joins(include_joins_of_closing_edge); + return d->m_caps_joins.number_joins(include_joins_of_closing_edge); } unsigned int @@ -4197,7 +1815,7 @@ join_chunk(unsigned int J) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_path_data.m_join_ordering.join_chunk(J); + return d->m_caps_joins.join_chunk(J); } unsigned int @@ -4205,8 +1823,11 @@ fastuidraw::StrokedPath:: chunk_of_joins(enum chunk_selection c) const { StrokedPathPrivate *d; + enum StrokedCapsJoins::chunk_selection cc; + d = static_cast(m_d); - return d->m_chunk_of_joins[c]; + cc = static_cast(c); + return d->m_caps_joins.chunk_of_joins(cc); } unsigned int @@ -4215,7 +1836,7 @@ chunk_of_caps(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_chunk_of_caps; + return d->m_caps_joins.chunk_of_caps(); } const fastuidraw::PainterAttributeData& @@ -4224,7 +1845,7 @@ square_caps(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_square_caps.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.square_caps(); } const fastuidraw::PainterAttributeData& @@ -4233,7 +1854,7 @@ adjustable_caps(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_adjustable_caps.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.adjustable_caps(); } const fastuidraw::PainterAttributeData& @@ -4242,7 +1863,7 @@ bevel_joins(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_bevel_joins.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.bevel_joins(); } const fastuidraw::PainterAttributeData& @@ -4251,7 +1872,7 @@ miter_clip_joins(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_miter_clip_joins.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.miter_clip_joins(); } const fastuidraw::PainterAttributeData& @@ -4260,7 +1881,7 @@ miter_bevel_joins(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_miter_bevel_joins.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.miter_bevel_joins(); } const fastuidraw::PainterAttributeData& @@ -4269,7 +1890,7 @@ miter_joins(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_miter_joins.data(d->m_path_data, d->m_subset); + return d->m_caps_joins.miter_joins(); } const fastuidraw::PainterAttributeData& @@ -4278,10 +1899,7 @@ rounded_joins(float thresh) const { StrokedPathPrivate *d; d = static_cast(m_d); - - return (!d->m_empty_path) ? - d->fetch_create(thresh, d->m_rounded_joins) : - d->m_empty_data; + return d->m_caps_joins.rounded_joins(thresh); } const fastuidraw::PainterAttributeData& @@ -4290,7 +1908,5 @@ rounded_caps(float thresh) const { StrokedPathPrivate *d; d = static_cast(m_d); - return (!d->m_empty_path) ? - d->fetch_create(thresh, d->m_rounded_caps) : - d->m_empty_data; + return d->m_caps_joins.rounded_caps(thresh); } From af1a52181fe0b4ffb25b43b623681c7b3552edb0 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Sat, 28 Apr 2018 11:33:04 +0300 Subject: [PATCH 13/52] fastuidraw/painter/stroked_caps_joins: minore cleanups Change-Id: I202db9e56a6ad77c8e9004e740d3c4979511ecd9 --- src/fastuidraw/painter/stroked_caps_joins.cpp | 387 ++++++++++-------- 1 file changed, 220 insertions(+), 167 deletions(-) diff --git a/src/fastuidraw/painter/stroked_caps_joins.cpp b/src/fastuidraw/painter/stroked_caps_joins.cpp index 01fb60fd6..0822e9349 100644 --- a/src/fastuidraw/painter/stroked_caps_joins.cpp +++ b/src/fastuidraw/painter/stroked_caps_joins.cpp @@ -144,90 +144,21 @@ namespace class PerContourData { public: - PerContourData(void): - m_cap_count(0) - {} + PerContourData(void); void start(const fastuidraw::vec2 &p, - const fastuidraw::vec2 &tangent_along_curve) - { - FASTUIDRAWassert(m_cap_count == 0); - m_caps[0].m_p = p; - m_caps[0].m_tangent_into_cap = -tangent_along_curve; - m_caps[0].m_distance_from_edge_start = 0.0f; - m_caps[0].m_distance_from_contour_start = 0.0f; - m_caps[0].m_is_starting_cap = true; - m_cap_count = 1; - } + const fastuidraw::vec2 &tangent_along_curve); void end(float distance_from_previous_join, - const fastuidraw::vec2 &direction_into_join) - { - fastuidraw::vec2 end_cap_pt, end_cap_direction; - float end_cap_edge_distance; - - /* the last added join starts the closing edge */ - if (!m_joins.empty()) - { - end_cap_pt = m_joins.back().m_p; - end_cap_direction = m_joins.back().m_tangent_into_join; - end_cap_edge_distance = m_joins.back().m_distance_from_previous_join; - m_joins.back().m_of_closing_edge = true; - - /* add the join ending the closing edge */ - add_join(m_caps[0].m_p, distance_from_previous_join, - direction_into_join, - -m_caps[0].m_tangent_into_cap); - m_joins.back().m_of_closing_edge = true; - } - else - { - end_cap_edge_distance = 0; - end_cap_pt = m_caps[0].m_p; - end_cap_direction = m_caps[0].m_tangent_into_cap; - } - - /* compute the contour lengths */ - float d(0.0f); - for(unsigned int i = 0, endi = m_joins.size(); i < endi; ++i) - { - d += m_joins[i].m_distance_from_previous_join; - m_joins[i].m_distance_from_contour_start = d; - } - - for (PerJoinData &J : m_joins) - { - J.m_closed_contour_length = d; - J.m_open_contour_length = d - distance_from_previous_join; - } - - for (PerCapData &C : m_caps) - { - C.m_closed_contour_length = m_joins.empty() ? 0.0f : d; - C.m_open_contour_length = m_joins.empty() ? distance_from_previous_join : d - distance_from_previous_join; - } - - m_caps[1].m_p = end_cap_pt; - m_caps[1].m_tangent_into_cap = end_cap_direction; - m_caps[1].m_distance_from_edge_start = end_cap_edge_distance; - m_caps[1].m_distance_from_contour_start = m_caps[1].m_open_contour_length; - m_caps[1].m_is_starting_cap = false; - - m_cap_count = 2; - } + const fastuidraw::vec2 &direction_into_join); void add_join(const fastuidraw::vec2 &p, float distance_from_previous_join, const fastuidraw::vec2 &tangent_into_join, - const fastuidraw::vec2 &tangent_leaving_join) - { - FASTUIDRAWassert(m_cap_count == 1); - m_joins.push_back(PerJoinData(p, distance_from_previous_join, - tangent_into_join, tangent_leaving_join)); - } + const fastuidraw::vec2 &tangent_leaving_join); const PerCapData& cap(unsigned int I) const @@ -239,30 +170,21 @@ namespace fastuidraw::c_array joins_of_non_closing_edges(void) const { - fastuidraw::c_array r; - if (m_joins.size() > 2) - { - r = fastuidraw::make_c_array(m_joins); - r = r.sub_array(0, m_joins.size() - 2); - } - return r; + FASTUIDRAWassert(m_cap_count == 2); + return m_joins_of_non_closing_edges; } fastuidraw::c_array - joins_of_closing_edges(void) const + joins_of_closing_edge(void) const { - fastuidraw::c_array r; - - r = fastuidraw::make_c_array(m_joins); - if (m_joins.size() > 2) - { - r = r.sub_array(m_joins.size() - 2); - } - return r; + FASTUIDRAWassert(m_cap_count == 2); + return m_joins_of_closing_edge; } private: std::vector m_joins; + fastuidraw::c_array m_joins_of_non_closing_edges; + fastuidraw::c_array m_joins_of_closing_edge; fastuidraw::vecN m_caps; unsigned int m_cap_count; }; @@ -305,61 +227,16 @@ namespace } void - add_join(const PerJoinData &src, unsigned int &chunk) - { - OrderingEntry J(src, chunk); - if (src.m_of_closing_edge) - { - m_closing_edge.push_back(J); - } - else - { - m_non_closing_edge.push_back(J); - } - ++chunk; - } + add_join(const PerJoinData &src, unsigned int &chunk); void post_process_non_closing(fastuidraw::range_type join_range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the joins must come in reverse - * so that higher depth values occlude later elements - */ - R = join_range.difference(); - d = depth + R - 1; - - for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_non_closing_edge.size()); - m_non_closing_edge[i].m_depth = d; - } - depth += R; - } + unsigned int &depth); void post_process_closing(unsigned int non_closing_edge_chunk_count, fastuidraw::range_type join_range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the joins must come in reverse - * so that higher depth values occlude later elements - */ - R = join_range.difference(); - d = depth + R - 1; - - for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_closing_edge.size()); - m_closing_edge[i].m_depth = d; - m_closing_edge[i].m_chunk += non_closing_edge_chunk_count; - } - depth += R; - } + unsigned int &depth); unsigned int number_joins(bool include_joins_of_closing_edge) const @@ -370,19 +247,7 @@ namespace } unsigned int - join_chunk(unsigned int J) const - { - FASTUIDRAWassert(J < number_joins(true)); - if (J >= m_non_closing_edge.size()) - { - J -= m_non_closing_edge.size(); - return m_closing_edge[J].m_chunk; - } - else - { - return m_non_closing_edge[J].m_chunk; - } - } + join_chunk(unsigned int J) const; private: std::vector > m_non_closing_edge; @@ -408,22 +273,7 @@ namespace void post_process(fastuidraw::range_type range, - unsigned int &depth) - { - unsigned int R, d; - - /* the depth values of the caps must come in reverse - * so that higher depth values occlude later elements - */ - R = range.difference(); - d = depth + R - 1; - for(unsigned int i = range.m_begin; i < range.m_end; ++i, --d) - { - FASTUIDRAWassert(i < m_caps.size()); - m_caps[i].m_depth = d; - } - depth += R; - } + unsigned int &depth); private: std::vector > m_caps; @@ -1187,6 +1037,209 @@ namespace } +///////////////////////////////// +// PerContourData methods +PerContourData:: +PerContourData(void): + m_cap_count(0) +{} + +void +PerContourData:: +start(const fastuidraw::vec2 &p, + const fastuidraw::vec2 &tangent_along_curve) +{ + FASTUIDRAWassert(m_cap_count == 0); + m_caps[0].m_p = p; + m_caps[0].m_tangent_into_cap = -tangent_along_curve; + m_caps[0].m_distance_from_edge_start = 0.0f; + m_caps[0].m_distance_from_contour_start = 0.0f; + m_caps[0].m_is_starting_cap = true; + m_cap_count = 1; +} + +void +PerContourData:: +end(float distance_from_previous_join, + const fastuidraw::vec2 &direction_into_join) +{ + fastuidraw::vec2 end_cap_pt, end_cap_direction; + float end_cap_edge_distance; + + /* the last added join starts the closing edge */ + if (!m_joins.empty()) + { + end_cap_pt = m_joins.back().m_p; + end_cap_direction = m_joins.back().m_tangent_into_join; + end_cap_edge_distance = m_joins.back().m_distance_from_previous_join; + m_joins.back().m_of_closing_edge = true; + + /* add the join ending the closing edge */ + add_join(m_caps[0].m_p, distance_from_previous_join, + direction_into_join, + -m_caps[0].m_tangent_into_cap); + m_joins.back().m_of_closing_edge = true; + } + else + { + end_cap_edge_distance = 0; + end_cap_pt = m_caps[0].m_p; + end_cap_direction = m_caps[0].m_tangent_into_cap; + } + + /* compute the contour lengths */ + float d(0.0f); + for(unsigned int i = 0, endi = m_joins.size(); i < endi; ++i) + { + d += m_joins[i].m_distance_from_previous_join; + m_joins[i].m_distance_from_contour_start = d; + } + + for (PerJoinData &J : m_joins) + { + J.m_closed_contour_length = d; + J.m_open_contour_length = d - distance_from_previous_join; + } + + for (PerCapData &C : m_caps) + { + C.m_closed_contour_length = m_joins.empty() ? 0.0f : d; + C.m_open_contour_length = m_joins.empty() ? distance_from_previous_join : d - distance_from_previous_join; + } + + m_caps[1].m_p = end_cap_pt; + m_caps[1].m_tangent_into_cap = end_cap_direction; + m_caps[1].m_distance_from_edge_start = end_cap_edge_distance; + m_caps[1].m_distance_from_contour_start = m_caps[1].m_open_contour_length; + m_caps[1].m_is_starting_cap = false; + + m_cap_count = 2; + + fastuidraw::c_array all_joins; + all_joins = fastuidraw::make_c_array(m_joins); + if (all_joins.size() > 2) + { + m_joins_of_non_closing_edges = all_joins.sub_array(0, all_joins.size() - 2); + m_joins_of_closing_edge = all_joins.sub_array(all_joins.size() - 2, 2); + } + else + { + m_joins_of_closing_edge = all_joins; + } +} + +void +PerContourData:: +add_join(const fastuidraw::vec2 &p, + float distance_from_previous_join, + const fastuidraw::vec2 &tangent_into_join, + const fastuidraw::vec2 &tangent_leaving_join) +{ + FASTUIDRAWassert(m_cap_count == 1); + m_joins.push_back(PerJoinData(p, distance_from_previous_join, + tangent_into_join, tangent_leaving_join)); +} + +////////////////////////////////// +// JoinOrdering methods +void +JoinOrdering:: +add_join(const PerJoinData &src, unsigned int &chunk) +{ + OrderingEntry J(src, chunk); + if (src.m_of_closing_edge) + { + m_closing_edge.push_back(J); + } + else + { + m_non_closing_edge.push_back(J); + } + ++chunk; +} + +void +JoinOrdering:: +post_process_non_closing(fastuidraw::range_type join_range, + unsigned int &depth) +{ + unsigned int R, d; + + /* the depth values of the joins must come in reverse + * so that higher depth values occlude later elements + */ + R = join_range.difference(); + d = depth + R - 1; + + for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_non_closing_edge.size()); + m_non_closing_edge[i].m_depth = d; + } + depth += R; +} + +void +JoinOrdering:: +post_process_closing(unsigned int non_closing_edge_chunk_count, + fastuidraw::range_type join_range, + unsigned int &depth) +{ + unsigned int R, d; + + /* the depth values of the joins must come in reverse + * so that higher depth values occlude later elements + */ + R = join_range.difference(); + d = depth + R - 1; + + for(unsigned int i = join_range.m_begin; i < join_range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_closing_edge.size()); + m_closing_edge[i].m_depth = d; + m_closing_edge[i].m_chunk += non_closing_edge_chunk_count; + } + depth += R; +} + +unsigned int +JoinOrdering:: +join_chunk(unsigned int J) const +{ + FASTUIDRAWassert(J < number_joins(true)); + if (J >= m_non_closing_edge.size()) + { + J -= m_non_closing_edge.size(); + return m_closing_edge[J].m_chunk; + } + else + { + return m_non_closing_edge[J].m_chunk; + } +} + +/////////////////////////// +// CapOrdering methods +void +CapOrdering:: +post_process(fastuidraw::range_type range, + unsigned int &depth) +{ + unsigned int R, d; + + /* the depth values of the caps must come in reverse + * so that higher depth values occlude later elements + */ + R = range.difference(); + d = depth + R - 1; + for(unsigned int i = range.m_begin; i < range.m_end; ++i, --d) + { + FASTUIDRAWassert(i < m_caps.size()); + m_caps[i].m_depth = d; + } + depth += R; +} + ///////////////////////////////// // CullingHierarchy methods CullingHierarchy* @@ -1217,7 +1270,7 @@ create(const ContourData &path_data) /* add all but the joins of the closing edge of C, i.e. all but * the last two joins */ - for(const PerJoinData &J : C.joins_of_closing_edges()) + for(const PerJoinData &J : C.joins_of_closing_edge()) { joins.push_back(J); } From 7859a41149ccfeb37ebb48c6a0643ec4f3488a22 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Sat, 28 Apr 2018 11:48:43 +0300 Subject: [PATCH 14/52] fastuidraw/painter/stroked_path: cleanups --- src/fastuidraw/painter/stroked_path.cpp | 125 ++++-------------------- 1 file changed, 20 insertions(+), 105 deletions(-) diff --git a/src/fastuidraw/painter/stroked_path.cpp b/src/fastuidraw/painter/stroked_path.cpp index 4dcf24b4b..b63725c9e 100644 --- a/src/fastuidraw/painter/stroked_path.cpp +++ b/src/fastuidraw/painter/stroked_path.cpp @@ -52,13 +52,6 @@ namespace StrokedPoint::depth_num_bits, depth); } - class PerEdgeData - { - public: - fastuidraw::vec2 m_begin_normal, m_end_normal; - fastuidraw::TessellatedPath::point m_start_pt, m_end_pt; - }; - template class OrderingEntry:public T { @@ -73,54 +66,6 @@ namespace unsigned int m_depth; }; - class PerContourData - { - public: - const PerEdgeData& - edge_data(unsigned int E) const - { - return (E == m_edge_data_store.size()) ? - m_edge_data_store[0]: - m_edge_data_store[E]; - } - - PerEdgeData& - write_edge_data(unsigned int E) - { - FASTUIDRAWassert(E < m_edge_data_store.size()); - return m_edge_data_store[E]; - } - - fastuidraw::vec2 m_begin_cap_normal, m_end_cap_normal; - fastuidraw::TessellatedPath::point m_start_contour_pt, m_end_contour_pt; - std::vector m_edge_data_store; - }; - - class ContourData:fastuidraw::noncopyable - { - public: - unsigned int - number_contours(void) const - { - return m_per_contour_data.size(); - } - - unsigned int - number_edges(unsigned int C) const - { - FASTUIDRAWassert(C < m_per_contour_data.size()); - return m_per_contour_data[C].m_edge_data_store.size(); - } - - std::vector m_per_contour_data; - }; - - class PathData:fastuidraw::noncopyable - { - public: - ContourData m_contour_data; - }; - class SingleSubEdge { public: @@ -163,7 +108,7 @@ namespace public: static SubEdgeCullingHierarchy* - create(const fastuidraw::TessellatedPath &P, ContourData &contour_data); + create(const fastuidraw::TessellatedPath &P); ~SubEdgeCullingHierarchy(); @@ -253,13 +198,13 @@ namespace static void - create_lists(const fastuidraw::TessellatedPath &P, ContourData &contour_data, + create_lists(const fastuidraw::TessellatedPath &P, std::vector &data, unsigned int &num_non_closing_edges, fastuidraw::BoundingBox &bx); static void - process_edge(const fastuidraw::TessellatedPath &P, ContourData &contour_data, + process_edge(const fastuidraw::TessellatedPath &P, unsigned int contour, unsigned int edge, std::vector &dst, fastuidraw::BoundingBox &bx); @@ -580,11 +525,11 @@ namespace } const fastuidraw::PainterAttributeData& - data(const PathData &P, const StrokedPathSubset *st) + data(const StrokedPathSubset *st) { if (!m_ready) { - m_data.set_data(T(P, st)); + m_data.set_data(T(st)); m_ready = true; } return m_data; @@ -621,7 +566,6 @@ namespace StrokedPathSubset* m_subset; fastuidraw::PainterAttributeData m_edges; - PathData m_path_data; fastuidraw::vecN m_chunk_of_edges; bool m_empty_path; @@ -694,36 +638,30 @@ const float SubEdgeCullingHierarchy::sm_mag_tol = 0.000001f; SubEdgeCullingHierarchy* SubEdgeCullingHierarchy:: -create(const fastuidraw::TessellatedPath &P, ContourData &path_data) +create(const fastuidraw::TessellatedPath &P) { std::vector data; fastuidraw::BoundingBox bx; unsigned int num_non_closing_edges; SubEdgeCullingHierarchy *return_value; - create_lists(P, path_data, data, num_non_closing_edges, bx); + create_lists(P, data, num_non_closing_edges, bx); return_value = FASTUIDRAWnew SubEdgeCullingHierarchy(bx, data, num_non_closing_edges); return return_value; } void SubEdgeCullingHierarchy:: -create_lists(const fastuidraw::TessellatedPath &P, ContourData &path_data, +create_lists(const fastuidraw::TessellatedPath &P, std::vector &data, unsigned int &num_non_closing_edges, fastuidraw::BoundingBox &bx) { - path_data.m_per_contour_data.resize(P.number_contours()); - - /* place data of closing sub-edges at the tail of the lists. - */ + /* place data of closing sub-edges at the tail of the lists. */ for(unsigned int o = 0; o < P.number_contours(); ++o) { - path_data.m_per_contour_data[o].m_edge_data_store.resize(P.number_edges(o)); - path_data.m_per_contour_data[o].m_start_contour_pt = P.unclosed_contour_point_data(o).front(); - path_data.m_per_contour_data[o].m_end_contour_pt = P.unclosed_contour_point_data(o).back(); for(unsigned int e = 0, ende = P.number_edges(o); e + 1 < ende; ++e) { - process_edge(P, path_data, o, e, data, bx); + process_edge(P, o, e, data, bx); } } @@ -732,14 +670,14 @@ create_lists(const fastuidraw::TessellatedPath &P, ContourData &path_data, { if (P.number_edges(o) > 0) { - process_edge(P, path_data, o, P.number_edges(o) - 1, data, bx); + process_edge(P, o, P.number_edges(o) - 1, data, bx); } } } void SubEdgeCullingHierarchy:: -process_edge(const fastuidraw::TessellatedPath &P, ContourData &path_data, +process_edge(const fastuidraw::TessellatedPath &P, unsigned int contour, unsigned int edge, std::vector &dst, fastuidraw::BoundingBox &bx) { @@ -773,12 +711,6 @@ process_edge(const fastuidraw::TessellatedPath &P, ContourData &path_data, sub_edge.m_bevel_lambda = 0.0f; sub_edge.m_has_bevel = false; sub_edge.m_bevel_normal = fastuidraw::vec2(0.0f, 0.0f); - path_data.m_per_contour_data[contour].write_edge_data(edge).m_begin_normal = normal; - path_data.m_per_contour_data[contour].write_edge_data(edge).m_start_pt = src_pts[i]; - if (edge == 0) - { - path_data.m_per_contour_data[contour].m_begin_cap_normal = normal; - } } else { @@ -799,23 +731,6 @@ process_edge(const fastuidraw::TessellatedPath &P, ContourData &path_data, last_normal = normal; } - - if (R.m_begin + 1 >= R.m_end) - { - path_data.m_per_contour_data[contour].write_edge_data(edge).m_begin_normal = normal; - path_data.m_per_contour_data[contour].write_edge_data(edge).m_start_pt = src_pts[R.m_begin]; - if (edge == 0) - { - path_data.m_per_contour_data[contour].m_begin_cap_normal = normal; - } - } - - path_data.m_per_contour_data[contour].write_edge_data(edge).m_end_normal = normal; - path_data.m_per_contour_data[contour].write_edge_data(edge).m_end_pt = src_pts[R.m_end - 1]; - if (edge + 2 == P.number_edges(contour)) - { - path_data.m_per_contour_data[contour].m_end_cap_normal = normal; - } } template @@ -1547,7 +1462,7 @@ ready_builder_contour(const fastuidraw::TessellatedPath *tess, fastuidraw::StrokedCapsJoins::Builder &b) { fastuidraw::c_array last_pts; - fastuidraw::vec2 delta, last_normal; + fastuidraw::vec2 delta, last_direction; float delta_mag; const float tol(0.000001f); @@ -1563,7 +1478,7 @@ ready_builder_contour(const fastuidraw::TessellatedPath *tess, { delta /= delta_mag; } - last_normal = delta; + last_direction = delta; b.begin_contour(last_pts[0].m_p, delta); for(unsigned int e = 1, ende = tess->number_edges(c); e < ende; ++e) @@ -1577,24 +1492,24 @@ ready_builder_contour(const fastuidraw::TessellatedPath *tess, mag = delta_into.magnitude(); if (mag < tol) { - delta_into = last_normal; + delta_into = last_direction; } else { delta_into /= mag; - last_normal = delta_into; + last_direction = delta_into; } delta_leaving = pts[1].m_p - pts[0].m_p; mag = delta_leaving.magnitude(); if (mag < tol) { - delta_leaving = last_normal; + delta_leaving = last_direction; } else { delta_leaving /= mag; - last_normal = delta_leaving; + last_direction = delta_leaving; } b.add_join(pts[0].m_p, @@ -1607,7 +1522,7 @@ ready_builder_contour(const fastuidraw::TessellatedPath *tess, delta_mag = delta.magnitude(); if (delta_mag < tol) { - delta = last_normal; + delta = last_direction; } else { @@ -1624,7 +1539,7 @@ create_edges(const fastuidraw::TessellatedPath &P) StrokedPathSubset::CreationValues cnts; FASTUIDRAWassert(!m_empty_path); - s = SubEdgeCullingHierarchy::create(P, m_path_data.m_contour_data); + s = SubEdgeCullingHierarchy::create(P); m_subset = StrokedPathSubset::create(s, cnts); m_edges.set_data(EdgeAttributeFiller(m_subset, P, cnts)); From 6f34de3460705c7c88c81aeedadc2b6c60877b81 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Sat, 28 Apr 2018 11:49:14 +0300 Subject: [PATCH 15/52] fastuidraw/glsl/shaders/painter: improvement for dashed shader-based anti-aliasing stroking without auxilary buffer Change-Id: Id059dc5944877ea7530f3d7e1b01ed38bd994528 --- ...w_painter_stroke.frag.glsl.resource_string | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.frag.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.frag.glsl.resource_string index 3e4a30b86..ba90248f0 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.frag.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.frag.glsl.resource_string @@ -66,6 +66,7 @@ fastuidraw_gl_frag_main(in uint sub_shader, for non-anti-aliased shading because it does not allow discard */ #ifdef FASTUIDRAW_STROKE_DASHED + if ((fastuidraw_stroking_dash_bits & uint(fastuidraw_stroke_gauranteed_to_be_covered_mask)) == 0u) { float d, q, fw; @@ -143,12 +144,12 @@ fastuidraw_gl_frag_main(in uint sub_shader, { if (render_pass == uint(fastuidraw_stroke_non_aa) && q <= 0.0) { - FASTUIDRAW_DISCARD; + alpha = 0.0; } if (render_pass == uint(fastuidraw_stroke_aa_pass1) && alpha < 1.0 - 1.0 / 255.0) { - FASTUIDRAW_DISCARD; + alpha = 0.0; } } #endif @@ -169,6 +170,20 @@ fastuidraw_gl_frag_main(in uint sub_shader, alpha = 0.0; } } + #elif defined(FASTUIDRAW_STROKE_DASHED) + { + float dd, q; + + // modulate by coverage to boundary + q = 1.0 - fastuidraw_stroking_on_boundary; + dd = max(q, fwidth(q)); + alpha *= q / dd; + + if (render_pass != uint(fastuidraw_stroke_aa_pass2) && alpha < 1.0 - 1.0 / 255.0) + { + FASTUIDRAW_DISCARD; + } + } #else { if (render_pass == uint(fastuidraw_stroke_aa_pass2)) From d7b8781e7ec07b25888e354b1bab2e406dccd992 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Sat, 28 Apr 2018 12:13:37 +0300 Subject: [PATCH 16/52] fastuidraw/glsl/shaders/painter: fix to dashed stroking --- .../fastuidraw_painter_stroke.vert.glsl.resource_string | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string index f0328983e..c525bb06a 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string @@ -486,9 +486,7 @@ fastuidraw_gl_vert_main(in uint sub_shader, edge. */ - //BUG: the code to collapse seems to kill something in a test it - // should not, for now just always expand - if (interval_id2 == interval_id && interval_id != -1 && false) + if (interval_id2 == interval_id && interval_id != -1 && dash_style != fastuidraw_stroke_dashed_flat_caps) { fastuidraw_stroking_dash_bits = uint(fastuidraw_stroke_gauranteed_to_be_covered_mask); fastuidraw_stroking_distance = 0.0f; From 127a39102d2752b5f4e0a6ccf08de253f2da2b9f Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 09:15:20 +0300 Subject: [PATCH 17/52] fastuidraw/painter/stroked_point: move lambda-negated concept to a bit mask In addition, remove offset_vector() and correctly document m_pre_offset and m_auxiliary_offset fields. Change-Id: Ie6607e7a335e841f3a17b86cc44d33bc9a8c81e5 --- inc/fastuidraw/painter/stroked_point.hpp | 296 +++++++++--------- inc/fastuidraw/tessellated_path.hpp | 2 +- src/fastuidraw/glsl/painter_backend_glsl.cpp | 2 +- ...w_painter_stroke.vert.glsl.resource_string | 11 +- src/fastuidraw/painter/stroked_caps_joins.cpp | 3 +- src/fastuidraw/painter/stroked_point.cpp | 75 ----- 6 files changed, 149 insertions(+), 240 deletions(-) diff --git a/inc/fastuidraw/painter/stroked_point.hpp b/inc/fastuidraw/painter/stroked_point.hpp index d1d8341bc..362d93965 100644 --- a/inc/fastuidraw/painter/stroked_point.hpp +++ b/inc/fastuidraw/painter/stroked_point.hpp @@ -40,89 +40,150 @@ class StrokedPoint public: /*! * \brief - * Enumeration for specifing how to compute - * \ref offset_vector()). + * Enumeration for specifing the point type which in turn + * determines the meaning of the fields \ref m_pre_offset + * and \ref m_auxiliary_offset */ enum offset_type_t { /*! - * The point is for an edge of the path, - * point signifies the start of a sub-edge - * (quad) of drawing an edge. + * The point is for an edge of the path, point signifies the start + * of a sub-edge (quad) of drawing an edge. The meanings of \ref + * m_pre_offset and \ref m_auxiliary_offset are: + * - \ref m_pre_offset the normal vector to the edge in which + * move the point by when stroking + * - \ref m_auxiliary_offset when added to \ref m_position, gives + * the position of the point on the other + * side of the edge. */ offset_start_sub_edge, /*! - * The point is for an edge of the path, - * point signifies the end of a sub-edge - * (quad) of drawing an edge. + * The point is for an edge of the path, point signifies the end + * of a sub-edge (quad) of drawing an edge. The meanings of the + * members \ref m_pre_offset and \ref m_auxiliary_offset are + * identical to \ref offset_start_sub_edge. */ offset_end_sub_edge, /*! - * The point is at a position that has the - * same value as point on an edge but the - * point itself is part of a cap or join. + * The point is at a position that has the same value as point on + * an edge but the point itself is part of a cap or join. The + * meanings of the members \ref m_pre_offset and \ref + * m_auxiliary_offset are: + * - \ref m_pre_offset the normal vector to the edge in which move + * the point by when stroking; this vector can + * be (0, 0). + * - \ref m_auxiliary_offset unused (set to (0, 0)) */ offset_shared_with_edge, /*! - * The point is for a boundary point of a rounded join of the path + * The point is for a boundary point of a rounded join of the path. + * The meanings of the members \ref m_pre_offset and and \ref + * m_auxiliary_offset are: + * - \ref m_pre_offset the .x() component holds the unit normal vector + * between the join point and the edge going into + * the join. The .y() component holds the unit + * normal vector between the join point and the edge + * leaving the join. The packing is that the + * x-coordinate value is given and the y-coordinate + * magnitude is \f$ sqrt(1 - x^2) \f$. If the bit + * \ref normal0_y_sign_bit is up, then the y-coordinate + * for the normal vector of going into the join, + * then the y-value is negative. If the bit \ref + * normal1_y_sign_bit is up, then the y-coordinate + * for the normal vector of leaving the join, then + * the y-value is negative. + * - \ref m_auxiliary_offset the .x() component gives an interpolation + * in the range [0, 1] to interpolate between + * the normal vectors packed in \ref m_pre_offset. + * The .y() value gives the normal vector directly + * but packed (as in \ref m_pre_offset) where the + * y-coordinate sign is negative if the bit \ref + * sin_sign_mask is up. */ offset_rounded_join, /*! - * Point type for miter-clip join point whose position - * depends on the miter-limit. + * Point type for miter-clip join point whose position depends on the + * stroking radius and the miter-limit. The meanings of \ref m_pre_offset + * and \ref m_auxiliary_offset are: + * - \ref m_pre_offset gives the unit normal vector of teh edge going + * into the join + * - \ref m_auxiliary_offset gives the unit normal vector of teh edge + * leaving the join */ offset_miter_clip_join, /*! - * Point type for miter-clip join point whose position - * depends on the miter-limit where the lambda of the - * computation is negatted. - */ - offset_miter_clip_join_lambda_negated, - - /*! - * Point type for miter-bevel join point whose position - * depends on the miter-limit. + * Point type for miter-bevel join point whose position depends on the + * stroking radius and the miter-limit. The meanings of \ref m_pre_offset + * and \ref m_auxiliary_offset are: + * - \ref m_pre_offset gives the unit normal vector of teh edge going + * into the join + * - \ref m_auxiliary_offset gives the unit normal vector of teh edge + * leaving the join */ offset_miter_bevel_join, /*! - * Point type for miter join whose position depends on - * the miter-limit. + * Point type for miter join whose position position depends on the + * stroking radius and the miter-limit. The meanings of \ref m_pre_offset + * and \ref m_auxiliary_offset are: + * - \ref m_pre_offset gives the unit normal vector of teh edge going + * into the join + * - \ref m_auxiliary_offset gives the unit normal vector of teh edge + * leaving the join */ offset_miter_join, /*! - * The point is for a boundary point of a rounded cap of the path + * The point is for a boundary point of a rounded cap of the path. + * The meanings of \ref m_pre_offset and \ref m_auxiliary_offset + * are: + * - \ref m_pre_offset is the normal vector to the path to start + * drawing the rounded cap + * - \ref m_auxiliary_offset gives the the unit vector (cos, sin) + * of the angle to make with the vector + * given by \ref m_pre_offset */ offset_rounded_cap, /*! - * The point is for a boundary point of a square cap of the path + * The point is for a boundary point of a square cap of the path, + * the meanings of \ref m_pre_offset and \ref m_auxiliary_offset are: + * - \ref m_pre_offset is the normal vector to the path by which + * to move the point + * - \ref m_auxiliary_offset is the tangent vector to the path + * by which to move the point */ offset_square_cap, /*! - * The point is from \ref adjustable_caps() point set. - * It is for a point for a cap at the start of a contour. - * These points are for dashed stroking with caps; they - * contain data to allow one from a vertex shader to extend - * or shrink the cap area correctly to implement dashed - * stroking. + * The point is a point of an adjustable cap. It is for a point for a + * cap at the start of a contour. These points are for dashed stroking + * with caps; they contain data to allow one from a vertex shader to + * extend or shrink the cap area correctly to implement dashed stroking. + * The meanings of \ref m_pre_offset and \ref m_auxiliary_offset are: + * - \ref m_pre_offset is the normal vector to the path by which + * to move the point; this value can be (0, 0) + * to indicate to not move perpindicular to the + * path + * - \ref m_auxiliary_offset is the tangent vector to the path + * by which to move the point; this value + * can be (0, 0) to indicate to not move + * parallel to the path */ offset_adjustable_cap_contour_start, /*! - * The point is from \ref adjustable_caps() point set. - * It is for a point for a cap at the end of a contour. - * These points are for dashed stroking with caps; they - * contain data to allow one from a vertex shader to extend - * or shrink the cap area correctly to implement dashed - * stroking. + * The point is a point of an adjustable cap. It is for a point for a + * cap at the end of a contour. These points are for dashed stroking + * with caps; they contain data to allow one from a vertex shader to + * extend or shrink the cap area correctly to implement dashed stroking. + * The meanings of \ref m_pre_offset and \ref m_auxiliary_offset are + * identical to the meanings for \ref offset_adjustable_cap_contour_start. */ offset_adjustable_cap_contour_end, @@ -217,6 +278,20 @@ class StrokedPoint sin_sign_bit, }; + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data + * for those with offset type \ref offset_miter_clip_join. + */ + enum packed_data_bit_layout_miter_join_t + { + /*! + * Indicates that the lambda of the miter-join + * computation should be negated. + */ + lambda_negated_bit = number_common_bits, + }; + /*! * \brief * Enumeration encoding of bits of point::m_packed_data for @@ -279,6 +354,11 @@ class StrokedPoint */ sin_sign_mask = FASTUIDRAW_MASK(sin_sign_bit, 1), + /*! + * Mask generated for \ref lambda_negated_mask + */ + lambda_negated_mask = FASTUIDRAW_MASK(lambda_negated_bit, 1), + /*! * Mask generated for \ref boundary_bit */ @@ -306,20 +386,24 @@ class StrokedPoint }; /*! - * The base position of a point, taken directly from - * the TessellatedPath from which the - * StrokedPath is constructed. + * The base position of a point before applying the stroking width + * to the position. */ vec2 m_position; /*! - * Gives the offset vector used to help compute - * the point offset vector. + * Gives values to help compute the location of the point after + * applying the stroking width. See the descriptions to the + * elements of \ref offset_type_t for its meaning for different + * offset types. */ vec2 m_pre_offset; /*! - * Provides an auxiliary offset data + * Gives values to help compute the location of the point after + * applying the stroking width. See the descriptions to the + * elements of \ref offset_type_t for its meaning for different + * offset types. */ vec2 m_auxiliary_offset; @@ -422,108 +506,8 @@ class StrokedPoint return unpack_bits(boundary_bit, 1u, m_packed_data); } - /*! - * Computes the offset vector for a point. The final position - * of a point when stroking with a width of W is given by - * \code - * m_position + 0.5f * W * offset_vector(). - * \endcode - * The computation for offset_vector() is as follows. - * - For those with offset_type() being \ref offset_start_sub_edge, - * \ref offset_end_sub_edge and \ref offset_shared_with_edge, - * the offset is given by - * \code - * m_pre_offset - * \endcode - * In addition, for these offset types, \ref m_auxiliary_offset - * holds the the delta vector to the point on edge with - * which the point makes a quad. - * - For those with offset_type() being \ref offset_rounded_join, - * the value is given by the following code - * \code - * vec2 cs; - * - * cs.x() = m_auxiliary_offset.y(); - * cs.y() = sqrt(1.0 - cs.x() * cs.x()); - * - * if (m_packed_data & sin_sign_mask) - * cs.y() = -cs.y(); - * - * offset = cs - * \endcode - * In addition, the source data for join is encoded as follows: - * \code - * float t; - * vec2 n0, n1; - * - * t = m_auxiliary_offset.x(); - * n0.x() = m_pre_offset.x(); - * n1.x() = m_pre_offset.y(); - * - * n0.y() = sqrt(1.0 - n0.x() * n0.x()); - * n1.y() = sqrt(1.0 - n1.x() * n1.x()); - * - * if (m_packed_data & normal0_y_sign_mask) - * n0.y() = -n0.y(); - * - * if (m_packed_data & normal1_y_sign_mask) - * n1.y() = -n1.y(); - * \endcode - * The vector n0 represents the normal of the path going into the join, - * the vector n1 represents the normal of the path going out of the join - * and t represents how much to interpolate from n0 to n1. - * - For those with offset_type() being \ref offset_miter_clip_join - * or \ref offset_miter_clip_join_lambda_negated - * the value is given by the following code - * \code - * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - * float r, det, lambda; - * det = dot(Jn1, n0); - * lambda = -t_sign(det); - * r = (det != 0.0) ? (dot(n0, n1) - 1.0) / det : 0.0; - * if (offset_type() == offset_miter_clip_join_lambda_negated) - * { - * lambda = -lambda; - * } - * //result: - * offset = lambda * (n + r * v); - * \endcode - * - For those with offset_type() being \ref offset_miter_join, - * or \ref offset_miter_bevel_join the value is given by the - * following code: - * \code - * vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - * vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - * float lambda, r, d; - * lambda = t_sign(dot(Jn0, n1)); - * r = lambda / (1.0 + dot(n0, n1)); - * offset = r * (n0 + n1); - * \endcode - * - For those with offset_type() being \ref offset_rounded_cap, - * the value is given by the following code - * \code - * vec2 n(m_pre_offset), v(n.y(), -n.x()); - * offset = m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; - * \endcode - * - For those with offset_type() being \ref offset_square_cap, - * \ref offset_adjustable_cap_contour_start or - * \ref offset_adjustable_cap_contour_end the value the value - * is given by - * \code - * m_pre_offset + m_auxiliary_offset - * \endcode - * In addition, \ref m_auxiliary_offset the tangent vector along - * the path in the direction of the path and \ref m_pre_offset - * holds a vector perpindicular to the path or a zero vector - * (indicating it is not on boundary of cap). - */ - vec2 - offset_vector(void); - /*! * When offset_type() is one of \ref offset_miter_clip_join, - * \ref offset_miter_clip_join_lambda_negated, * \ref offset_miter_bevel_join or \ref offset_miter_join, * returns the distance to the miter point. For other point * types, returns 0.0. @@ -532,17 +516,17 @@ class StrokedPoint miter_distance(void) const; /*! - * Pack the data of this \ref point into a \ref + * Pack the data of this \ref StrokedPoint into a \ref * PainterAttribute. The packing is as follows: - * - PainterAttribute::m_attrib0 .xy -> point::m_position (float) - * - PainterAttribute::m_attrib0 .zw -> point::m_pre_offset (float) - * - PainterAttribute::m_attrib1 .x -> point::m_distance_from_edge_start (float) - * - PainterAttribute::m_attrib1 .y -> point::m_distance_from_contour_start (float) - * - PainterAttribute::m_attrib1 .zw -> point::m_auxiliary_offset (float) - * - PainterAttribute::m_attrib2 .x -> point::m_packed_data (uint) - * - PainterAttribute::m_attrib2 .y -> point::m_edge_length (float) - * - PainterAttribute::m_attrib2 .z -> point::m_open_contour_length (float) - * - PainterAttribute::m_attrib2 .w -> point::m_closed_contour_length (float) + * - PainterAttribute::m_attrib0 .xy -> \ref m_position (float) + * - PainterAttribute::m_attrib0 .zw -> \ref m_pre_offset (float) + * - PainterAttribute::m_attrib1 .x -> \ref m_distance_from_edge_start (float) + * - PainterAttribute::m_attrib1 .y -> \ref m_distance_from_contour_start (float) + * - PainterAttribute::m_attrib1 .zw -> \ref m_auxiliary_offset (float) + * - PainterAttribute::m_attrib2 .x -> \ref m_packed_data (uint) + * - PainterAttribute::m_attrib2 .y -> \ref m_edge_length (float) + * - PainterAttribute::m_attrib2 .z -> \ref m_open_contour_length (float) + * - PainterAttribute::m_attrib2 .w -> \ref m_closed_contour_length (float) * * \param dst PainterAttribute to which to pack */ @@ -550,7 +534,7 @@ class StrokedPoint pack_point(PainterAttribute *dst) const; /*! - * Unpack a \ref point from a \ref PainterAttribute. + * Unpack a \ref StrokedPoint from a \ref PainterAttribute. * \param dst point to which to unpack data * \param src PainterAttribute from which to unpack data */ diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index ed41f1938..afcabb571 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -162,7 +162,7 @@ class TessellatedPath: /*! * Specifies the meaning of \ref m_threshhold. - * Default value is \ref threshhold_curvature. + * Default value is \ref threshhold_curve_distance. */ enum threshhold_type_t m_threshhold_type; diff --git a/src/fastuidraw/glsl/painter_backend_glsl.cpp b/src/fastuidraw/glsl/painter_backend_glsl.cpp index 20d065d2a..c4c25d937 100644 --- a/src/fastuidraw/glsl/painter_backend_glsl.cpp +++ b/src/fastuidraw/glsl/painter_backend_glsl.cpp @@ -501,7 +501,6 @@ add_enums(fastuidraw::glsl::ShaderSource &src) .add_macro("fastuidraw_stroke_offset_miter_bevel_join", StrokedPoint::offset_miter_bevel_join) .add_macro("fastuidraw_stroke_offset_miter_join", StrokedPoint::offset_miter_join) .add_macro("fastuidraw_stroke_offset_miter_clip_join", StrokedPoint::offset_miter_clip_join) - .add_macro("fastuidraw_stroke_offset_miter_clip_join_lambda_negated", StrokedPoint::offset_miter_clip_join_lambda_negated) .add_macro("fastuidraw_stroke_offset_rounded_cap", StrokedPoint::offset_rounded_cap) .add_macro("fastuidraw_stroke_offset_square_cap", StrokedPoint::offset_square_cap) @@ -515,6 +514,7 @@ add_enums(fastuidraw::glsl::ShaderSource &src) .add_macro("fastuidraw_stroke_sin_sign_mask", StrokedPoint::sin_sign_mask) .add_macro("fastuidraw_stroke_normal0_y_sign_mask", StrokedPoint::normal0_y_sign_mask) .add_macro("fastuidraw_stroke_normal1_y_sign_mask", StrokedPoint::normal1_y_sign_mask) + .add_macro("fastuidraw_stroke_lambda_negaged_mask", StrokedPoint::lambda_negated_mask) .add_macro("fastuidraw_stroke_boundary_bit", StrokedPoint::boundary_bit) .add_macro("fastuidraw_stroke_join_mask", StrokedPoint::join_mask) .add_macro("fastuidraw_stroke_bevel_edge_mask", StrokedPoint::bevel_edge_mask) diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string index c525bb06a..4e3924179 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string @@ -10,8 +10,7 @@ fastuidraw_stroke_compute_offset(in uint point_packed_data, in float miter_limit, out vec2 offset) { - if (offset_type == fastuidraw_stroke_offset_miter_clip_join - || offset_type == fastuidraw_stroke_offset_miter_clip_join_lambda_negated) + if (offset_type == fastuidraw_stroke_offset_miter_clip_join) { vec2 n0 = pre_offset, Jn0 = vec2(n0.y, -n0.x); vec2 n1 = auxiliary_offset, Jn1 = vec2(n1.y, -n1.x); @@ -21,7 +20,7 @@ fastuidraw_stroke_compute_offset(in uint point_packed_data, lambda = -sign(det); r = (det != 0.0) ? (dot(n0, n1) - 1.0) / det : 0.0; - if (offset_type == fastuidraw_stroke_offset_miter_clip_join_lambda_negated) + if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0) { lambda = -lambda; } @@ -103,8 +102,7 @@ fastuidraw_stroke_compute_offset_pixels(in uint point_packed_data, out vec2 offset, inout float stroke_radius) { - if (offset_type == fastuidraw_stroke_offset_miter_clip_join - || offset_type == fastuidraw_stroke_offset_miter_clip_join_lambda_negated) + if (offset_type == fastuidraw_stroke_offset_miter_clip_join) { vec2 n0 = pre_offset, v0 = vec2(n0.y, -n0.x); vec2 n1 = auxiliary_offset, v1 = vec2(n1.y, -n1.x); @@ -113,7 +111,8 @@ fastuidraw_stroke_compute_offset_pixels(in uint point_packed_data, float det, r, r0, r1, lambda; lambda = -sign(dot(v1, n0)); - if (offset_type == fastuidraw_stroke_offset_miter_clip_join_lambda_negated) + + if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0) { lambda = -lambda; } diff --git a/src/fastuidraw/painter/stroked_caps_joins.cpp b/src/fastuidraw/painter/stroked_caps_joins.cpp index 0822e9349..b2931b7c0 100644 --- a/src/fastuidraw/painter/stroked_caps_joins.cpp +++ b/src/fastuidraw/painter/stroked_caps_joins.cpp @@ -2288,7 +2288,8 @@ fill_join_implement(unsigned int join_id, const PerJoinData &J, pt.m_position = J.m_p; pt.m_pre_offset = J.n1(); pt.m_auxiliary_offset = J.n0(); - pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join_lambda_negated, depth); + pt.m_packed_data = pack_data_join(1, fastuidraw::StrokedPoint::offset_miter_clip_join, depth); + pt.m_packed_data |= fastuidraw::StrokedPoint::lambda_negated_mask; pt.pack_point(&pts[vertex_offset]); ++vertex_offset; diff --git a/src/fastuidraw/painter/stroked_point.cpp b/src/fastuidraw/painter/stroked_point.cpp index e13cb86f5..92dcadf7d 100644 --- a/src/fastuidraw/painter/stroked_point.cpp +++ b/src/fastuidraw/painter/stroked_point.cpp @@ -43,80 +43,6 @@ unpack_point(StrokedPoint *dst, const PainterAttribute &a) dst->m_closed_contour_length = unpack_float(a.m_attrib2.w()); } -fastuidraw::vec2 -fastuidraw::StrokedPoint:: -offset_vector(void) -{ - enum offset_type_t tp; - - tp = offset_type(); - - switch(tp) - { - case offset_start_sub_edge: - case offset_end_sub_edge: - case offset_shared_with_edge: - return m_pre_offset; - - case offset_square_cap: - return m_pre_offset + m_auxiliary_offset; - - case offset_rounded_cap: - { - vec2 n(m_pre_offset), v(n.y(), -n.x()); - return m_auxiliary_offset.x() * v + m_auxiliary_offset.y() * n; - } - - case offset_miter_clip_join: - case offset_miter_clip_join_lambda_negated: - { - vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - float r, det, lambda; - - det = dot(Jn1, n0); - lambda = -t_sign(det); - r = (det != 0.0f) ? (dot(n0, n1) - 1.0f) / det : 0.0f; - - if (tp == offset_miter_clip_join_lambda_negated) - { - lambda = -lambda; - } - - return lambda * (n0 + r * Jn0); - } - - case offset_miter_bevel_join: - case offset_miter_join: - { - vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); - vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); - float r, lambda, den; - - lambda = t_sign(dot(Jn0, n1)); - den = 1.0f + dot(n0, n1); - r = (den != 0.0f) ? lambda / den : 0.0f; - return r * (n0 + n1); - } - - case offset_rounded_join: - { - vec2 cs; - - cs.x() = m_auxiliary_offset.y(); - cs.y() = sqrt(1.0 - cs.x() * cs.x()); - if (m_packed_data & sin_sign_mask) - { - cs.y() = -cs.y(); - } - return cs; - } - - default: - return vec2(0.0f, 0.0f); - } -} - float fastuidraw::StrokedPoint:: miter_distance(void) const @@ -127,7 +53,6 @@ miter_distance(void) const switch(tp) { case offset_miter_clip_join: - case offset_miter_clip_join_lambda_negated: { vec2 n0(m_pre_offset), Jn0(n0.y(), -n0.x()); vec2 n1(m_auxiliary_offset), Jn1(n1.y(), -n1.x()); From 657ee00b67a28081107317052ffe25bf5542da96 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 11:10:07 +0300 Subject: [PATCH 18/52] Makefile: add static library targets --- .gitignore | 5 +++++ fastuidraw-config.in | 20 ++++++++++++++++---- make/Makefile.base.lib.mk | 15 ++++++++++++--- make/Makefile.egl.lib.mk | 14 +++++++++++++- make/Makefile.gl_backend.lib.mk | 26 +++++++++++++++++++------- n.pc.in | 4 ++-- 6 files changed, 67 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index e9d3d1fae..d61ae9f72 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ build/ *.exe *.clang_tidy *.pc +*.a inc/fastuidraw/gl_backend/ngl_gl.hpp src/fastuidraw/gl_backend/ngl_gl.cpp inc/fastuidraw/gl_backend/ngl_gles3.hpp @@ -17,5 +18,9 @@ src/fastuidraw/ngl_egl.cpp *-GL-debug *-GLES-release *-GLES-debug +*-GL-release-static +*-GL-debug-static +*-GLES-release-static +*-GLES-debug-static fastuidraw-config.nodir fastuidraw-config diff --git a/fastuidraw-config.in b/fastuidraw-config.in index c6856fbcb..2b212d150 100644 --- a/fastuidraw-config.in +++ b/fastuidraw-config.in @@ -33,6 +33,8 @@ fi mode=unknown +static_linking=0 + print_cflags=0 print_libs=0 print_dirs=1 @@ -80,6 +82,7 @@ while test $# -gt 0; do --ngl) add_ngl=1 ;; --ngles) add_ngles=1 ;; --negl) add_negl=1 ;; + --static) static_linking=1 ;; --help) printhelp=1 ;; *) print_help @@ -92,11 +95,11 @@ cflags= base_cflags= libs= -base_libs= +dir_libs= if [ "$print_dirs" = "1" ]; then base_cflags=-I$include_location - base_libs=-L$lib_location + dir_libs=-L$lib_location fi if [ "$printhelp" = "1" ]; then @@ -121,7 +124,8 @@ if [ "$print_cflags" = "1" ] || [ "$print_libs" = "1" ]; then fi fi -libs="@FASTUIDRAW_LIBS@ $base_libs -lFastUIDraw_$mode" +base_libs="@FASTUIDRAW_LIBS@" +libs="$dir_libs -lFastUIDraw_$mode" cflags="$base_cflags" if [ "$mode" = "release" ]; then @@ -157,6 +161,14 @@ if [ "$print_cflags" = "1" ]; then echo $cflags fi +if [ "$static_linking" = "1" ]; then + pre_link="-Wl,--whole-archive -Wl,-Bstatic" + post_link="-Wl,--no-whole-archive -Wl,-Bdynamic" +else + pre_link= + post_link= +fi + if [ "$print_libs" = "1" ]; then - echo $libs + echo $pre_link $libs $post_link $base_libs fi diff --git a/make/Makefile.base.lib.mk b/make/Makefile.base.lib.mk index 5c0150578..b2a69d7cb 100644 --- a/make/Makefile.base.lib.mk +++ b/make/Makefile.base.lib.mk @@ -1,4 +1,4 @@ -FASTUIDRAW_LIBS += $(shell freetype-config --libs) -lm +FASTUIDRAW_LIBS += $(shell freetype-config --libs) FASTUIDRAW_BASE_CFLAGS = -std=c++11 -D_USE_MATH_DEFINES FASTUIDRAW_debug_BASE_CFLAGS = $(FASTUIDRAW_BASE_CFLAGS) -DFASTUIDRAW_DEBUG @@ -55,6 +55,7 @@ build/$(1)/private/%.o: %.cpp build/$(1)/private/%.d build/$(1)/private/%.d: ; .PRECIOUS: build/$(1)/%.d +TARGET_LIST += libFastUIDraw_$(1) ifeq ($(MINGW_BUILD),1) libFastUIDraw_$(1): libFastUIDraw_$(1).dll @@ -75,14 +76,22 @@ INSTALL_LIBS += libFastUIDraw_$(1).so .PHONY: libFastUIDraw_$(1) libFastUIDraw endif +libFastUIDraw-static: libFastUIDraw_$(1)-static +.PHONY: libFastUIDraw-static +libFastUIDraw_$(1)-static: libFastUIDraw_$(1).a +.PHONY: libFastUIDraw_$(1)-static +libFastUIDraw_$(1).a: $(FASTUIDRAW_STRING_RESOURCES_SRCS) $$(FASTUIDRAW_$(1)_ALL_OBJS) + ar rcs $$@ $$(FASTUIDRAW_$(1)_ALL_OBJS) +CLEAN_FILES += libFastUIDraw_$(1).a +TARGETLIST += libFastUIDraw_$(1)-static + -include $$(FASTUIDRAW_$(1)_DEPS) libFastUIDraw: libFastUIDraw_$(1) ) endef -TARGETLIST += libFastUIDraw -TARGETLIST += libFastUIDraw_debug libFastUIDraw_release +TARGETLIST += libFastUIDraw libFastUIDraw-static $(call librules,release) $(call librules,debug) all: libFastUIDraw diff --git a/make/Makefile.egl.lib.mk b/make/Makefile.egl.lib.mk index 5d23b0799..8913b8a55 100644 --- a/make/Makefile.egl.lib.mk +++ b/make/Makefile.egl.lib.mk @@ -14,15 +14,27 @@ build/NEGL/$(1)/%.d: ; libNEGL_$(1): libNEGL_$(1).so libNEGL_$(1).so: $$(NEGL_OBJS_$(1)) libFastUIDraw_$(1).so - $(CXX) -shared -Wl,-soname,libNEGL_$(1).so -o libNEGL_$(1).so $$(NEGL_OBJS_$(1)) -lEGL -L. -lFastUIDraw_$(1) $(FASTUIDRAW_LIBS) + $(CXX) -shared -Wl,-soname,libNEGL_$(1).so -o libNEGL_$(1).so $$(NEGL_OBJS_$(1)) -lEGL -L. -lFastUIDraw_$(1) $(FASTUIDRAW_DEPS_LIBS) CLEAN_FILES += libNEGL_$(1).so INSTALL_LIBS += libNEGL_$(1).so libNEGL: libNEGL_$(1) .PHONY: libNEGL_$(1) libNEGL + +libNEGL_$(1):libNEGL_$(1).a +libNEGL_$(1).a: $$(NEGL_OBJS_$(1)) + ar rcs $$@ $$(NEGL_OBJS_$(1)) +CLEAN_FILES += libNEGL_$(1).a + +TARGETLIST += libNEGL_$(1)-static +libNEGL_$(1)-static: libNEGL_$(1).a +.PHONY: libNEGL_$(1)-static +libNEGL-static: libNEGL_$(1).a +.PHONY: libNEGL ) endef ifeq ($(BUILD_NEGL),1) $(call egllibrules,release) $(call egllibrules,debug) +TARGETLIST += libNEGL-static endif diff --git a/make/Makefile.gl_backend.lib.mk b/make/Makefile.gl_backend.lib.mk index abd81c2a8..93b9622a8 100644 --- a/make/Makefile.gl_backend.lib.mk +++ b/make/Makefile.gl_backend.lib.mk @@ -57,8 +57,6 @@ libN$(1)_$(2): libN$(1)_$(2).dll.a libN$(1)_$(2).dll.a: libN$(1)_$(2).dll libN$(1)_$(2).dll: $$(NGL_$(1)_$(2)_OBJ) libFastUIDraw_$(2) $(CXX) -shared -Wl,--out-implib,libN$(1)_$(2).dll.a -o libN$(1)_$(2).dll $$(NGL_$(1)_$(2)_OBJ) -L. $$(FASTUIDRAW_$(2)_LIBS) -LIBFASTUIDRAW_$(1)_$(2) = libFastUIDraw$(1)_$(2).dll.a -LIBN$(1)_$(2) = libN$(1)_$(2).dll.a INSTALL_LIBS += libFastUIDraw$(1)_$(2).dll.a libN$(1)_$(2).dll.a INSTALL_EXES += libFastUIDraw$(1)_$(2).dll libN$(1)_$(2).dll else @@ -68,11 +66,22 @@ libFastUIDraw$(1)_$(2).so: libFastUIDraw_$(2).so libN$(1)_$(2).so $$(FASTUIDRAW_ libN$(1)_$(2): libN$(1)_$(2).so libN$(1)_$(2).so: $$(NGL_$(1)_$(2)_OBJ) libFastUIDraw_$(2) $(CXX) -shared -Wl,-soname,libN$(1)_$(2).so -o libN$(1)_$(2).so $$(NGL_$(1)_$(2)_OBJ) -L. $$(FASTUIDRAW_$(2)_LIBS) -LIBFASTUIDRAW_$(1)_$(2) = libFastUIDraw$(1)_$(2).so -LIBN$(1)_$(2) = libN$(1)_$(2).so INSTALL_LIBS += libFastUIDraw$(1)_$(2).so libN$(1)_$(2).so endif +libFastUIDraw$(1)_$(2)-static: libFastUIDraw$(1)_$(2).a +.PHONY: libFastUIDraw$(1)_$(2)-static +libFastUIDraw$(1)_$(2).a: $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) libN$(1)_$(2).a + ar rcs $$@ $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) + +libN$(1)_$(2)-static: libN$(1)_$(2).a +.PHONY: libN$(1)_$(2)-static +libN$(1)_$(2).a: $$(NGL_$(1)_$(2)_OBJ) + ar rcs $$@ $$(NGL_$(1)_$(2)_OBJ) + +CLEAN_FILES += libFastUIDraw$(1)_$(2).a libN$(1)_$(2).a +TARGETLIST += libN$(1)_$(2)-static libFastUIDraw$(1)_$(2)-static + endif ) endef @@ -83,17 +92,20 @@ define glrules $(eval $(call glrule,$(1),release,$(2)) $(call glrule,$(1),debug,$(2)) ifeq ($(2),1) -TARGETLIST += libFastUIDraw$(1) libFastUIDraw$(1)_debug libFastUIDraw$(1)_release +TARGETLIST += libFastUIDraw$(1) libFastUIDraw$(1)-static libFastUIDraw$(1)_debug libFastUIDraw$(1)_release libFastUIDraw$(1): libFastUIDraw$(1)_debug libFastUIDraw$(1)_release +libFastUIDraw$(1)-static: libFastUIDraw$(1)_release-static libFastUIDraw$(1)_debug-static .PHONY: libFastUIDraw$(1) .PHONY: libFastUIDraw$(1)_release .PHONY: libFastUIDraw$(1)_debug libN$(1): libN$(1)_debug libN$(1)_release -TARGETLIST += libN$(1) libN$(1)_debug libN$(1)_release -all: libFastUIDraw$(1) libN$(1) +libN$(1)-static: libN$(1)_debug-static libN$(1)_release-static +TARGETLIST += libN$(1) libN$(1)_debug libN$(1)_release libN$(1)-static +all: libFastUIDraw$(1)-static libFastUIDraw$(1) libN$(1) libN$(1)-static .PHONY: libN$(1) .PHONY: libN$(1)_debug .PHONY: libN$(1)_release +.PHONY: static-libs-$(1) endif ) endef diff --git a/n.pc.in b/n.pc.in index c27f292e7..e4c7b8ace 100644 --- a/n.pc.in +++ b/n.pc.in @@ -9,5 +9,5 @@ Version: Requires: fastuidraw-@TYPE@ Conflicts: n@API@-@OTHER_TYPE@ n@OTHER_API@-@TYPE@ n@OTHER_API@-@OTHER_TYPE@ Cflags: -Libs: -L${libdir} -lN@API@_@TYPE@ @N_ADDITIONAL_LIBS@ -Libs.private: +Libs: -L${libdir} -lN@API@_@TYPE@ +Libs.private: @N_ADDITIONAL_LIBS@ From f5d3369637cfb01edbd5cbed72a80a5b53ef30dd Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 11:43:50 +0300 Subject: [PATCH 19/52] Makefile: add INSTALL_STATIC option Change-Id: Iaceb912dd6b5781a8bb068788ba433fd2774c4c8 --- Makefile | 6 +++++- make/Makefile.egl.lib.mk | 1 + make/Makefile.gl_backend.lib.mk | 1 + make/Makefile.install.mk | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cfef2b417..96a173d7b 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,11 @@ ENVIRONMENTALDESCRIPTIONS := #install location INSTALL_LOCATION ?= /usr/local -ENVIRONMENTALDESCRIPTIONS += "INSTALL_LOCATION: provides install location (default /usr/local)" +ENVIRONMENTALDESCRIPTIONS += "INSTALL_LOCATION: provides install location (default /usr/local)" + +INSTALL_STATIC ?= 0 +ENVIRONMENTALDESCRIPTIONS += "INSTALL_STATIC: if 1, install static libraries (default 0)" + # Mark all intermediate files as secondary and precious .PRECIOUS: .SECONDARY: diff --git a/make/Makefile.egl.lib.mk b/make/Makefile.egl.lib.mk index 8913b8a55..ed2a91232 100644 --- a/make/Makefile.egl.lib.mk +++ b/make/Makefile.egl.lib.mk @@ -24,6 +24,7 @@ libNEGL_$(1):libNEGL_$(1).a libNEGL_$(1).a: $$(NEGL_OBJS_$(1)) ar rcs $$@ $$(NEGL_OBJS_$(1)) CLEAN_FILES += libNEGL_$(1).a +INSTALL_STATIC_LIBS += libNEGL_$(1).a TARGETLIST += libNEGL_$(1)-static libNEGL_$(1)-static: libNEGL_$(1).a diff --git a/make/Makefile.gl_backend.lib.mk b/make/Makefile.gl_backend.lib.mk index 93b9622a8..9b4ace8af 100644 --- a/make/Makefile.gl_backend.lib.mk +++ b/make/Makefile.gl_backend.lib.mk @@ -81,6 +81,7 @@ libN$(1)_$(2).a: $$(NGL_$(1)_$(2)_OBJ) CLEAN_FILES += libFastUIDraw$(1)_$(2).a libN$(1)_$(2).a TARGETLIST += libN$(1)_$(2)-static libFastUIDraw$(1)_$(2)-static +INSTALL_STATIC_LIBS += libFastUIDraw$(1)_$(2).a libN$(1)_$(2).a endif ) diff --git a/make/Makefile.install.mk b/make/Makefile.install.mk index 1d44fac69..fc0935129 100644 --- a/make/Makefile.install.mk +++ b/make/Makefile.install.mk @@ -100,6 +100,9 @@ $(call pkgconfrulesapi,$(1),GL,$(BUILD_GL)) $(call pkgconfrulesapi,$(1),GLES,$(BUILD_GLES))) endef +ifeq ($(INSTALL_STATIC),1) +INSTALL_LIBS += $(INSTALL_STATIC_LIBS) +endif $(call pkgconfrules,release) $(call pkgconfrules,debug) From 2b9830356975f40dded359cfd05b0145a57e07a5 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 11:44:26 +0300 Subject: [PATCH 20/52] fastuidraw.pc: remove unnecessary -lm Change-Id: Iff0f7f46d369d6c723f69f75b2297acb916eee4c --- fastuidraw.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastuidraw.pc.in b/fastuidraw.pc.in index 902913c3c..fa9ebf70f 100644 --- a/fastuidraw.pc.in +++ b/fastuidraw.pc.in @@ -9,5 +9,5 @@ Version: Requires: freetype2 Conflicts: fastuidraw-@OTHER_TYPE@ Cflags: -I${includedir} @FASTUIDRAW_CFLAGS@ -Libs: -L${libdir} -lFastUIDraw_@TYPE@ -lm +Libs: -L${libdir} -lFastUIDraw_@TYPE@ Libs.private: From 4eaee4a4a5b8e065f89a4b18d4d21631216c7c66 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 11:57:23 +0300 Subject: [PATCH 21/52] fastuidraw/glsl/shaders: GLES fix Change-Id: Ib9456db351978e301e2e44c64fbed836fa52f26a --- .../fastuidraw_painter_stroke.vert.glsl.resource_string | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string index 4e3924179..faf90cd80 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string @@ -20,7 +20,7 @@ fastuidraw_stroke_compute_offset(in uint point_packed_data, lambda = -sign(det); r = (det != 0.0) ? (dot(n0, n1) - 1.0) / det : 0.0; - if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0) + if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0u) { lambda = -lambda; } @@ -112,7 +112,7 @@ fastuidraw_stroke_compute_offset_pixels(in uint point_packed_data, lambda = -sign(dot(v1, n0)); - if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0) + if ((uint(fastuidraw_stroke_lambda_negaged_mask) & point_packed_data) != 0u) { lambda = -lambda; } From 915ac710b6b9730eb6e34d32dab246d14ea64a98 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 12:16:40 +0300 Subject: [PATCH 22/52] Makefile: default output readability tweaks Change-Id: Ic2ab91dda8e4939647bb24449a5cef62516ec0f4 --- Makefile | 2 +- make/Makefile.demo.rules.mk | 6 ++++-- make/Makefile.egl.lib.mk | 3 +-- make/Makefile.gl_backend.lib.mk | 5 ++--- make/Makefile.install.mk | 3 --- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 96a173d7b..569059432 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ INSTALL_LOCATION ?= /usr/local ENVIRONMENTALDESCRIPTIONS += "INSTALL_LOCATION: provides install location (default /usr/local)" INSTALL_STATIC ?= 0 -ENVIRONMENTALDESCRIPTIONS += "INSTALL_STATIC: if 1, install static libraries (default 0)" +ENVIRONMENTALDESCRIPTIONS += "INSTALL_STATIC: if 1, install static libraries (default 0). NOTE: if linking static libs, make sure one links in the entire archive (for example via the linker option --whole-archive (from g++ do -Wl,--whole-archive)" # Mark all intermediate files as secondary and precious .PRECIOUS: diff --git a/make/Makefile.demo.rules.mk b/make/Makefile.demo.rules.mk index e1508ab16..f6753c248 100644 --- a/make/Makefile.demo.rules.mk +++ b/make/Makefile.demo.rules.mk @@ -93,11 +93,14 @@ $(eval $(call demobuildrules,$(1),$(2)) $(foreach demoname,$(DEMOS),$(call demorule,$(demoname),$(1),$(2),$(3))) ifeq ($(3),1) .PHONY: demos-$(1)-$(2) -TARGETLIST += demos-$(1)-$(2) endif ) endef + + +TARGETLIST+=demos demos-debug demos-release + # $1 --> gl or gles # $2 --> (0: skip build targets, 1: add build targets) define demosapi @@ -117,5 +120,4 @@ endef $(call demosapi,GL,$(BUILD_GL)) $(call demosapi,GLES,$(BUILD_GLES)) demos: demos-debug demos-release -TARGETLIST+=demos demos-debug demos-release all: demos diff --git a/make/Makefile.egl.lib.mk b/make/Makefile.egl.lib.mk index ed2a91232..ad8b35112 100644 --- a/make/Makefile.egl.lib.mk +++ b/make/Makefile.egl.lib.mk @@ -26,7 +26,6 @@ libNEGL_$(1).a: $$(NEGL_OBJS_$(1)) CLEAN_FILES += libNEGL_$(1).a INSTALL_STATIC_LIBS += libNEGL_$(1).a -TARGETLIST += libNEGL_$(1)-static libNEGL_$(1)-static: libNEGL_$(1).a .PHONY: libNEGL_$(1)-static libNEGL-static: libNEGL_$(1).a @@ -37,5 +36,5 @@ endef ifeq ($(BUILD_NEGL),1) $(call egllibrules,release) $(call egllibrules,debug) -TARGETLIST += libNEGL-static +TARGETLIST += libNEGL libNEGL-static endif diff --git a/make/Makefile.gl_backend.lib.mk b/make/Makefile.gl_backend.lib.mk index 9b4ace8af..c14de5dff 100644 --- a/make/Makefile.gl_backend.lib.mk +++ b/make/Makefile.gl_backend.lib.mk @@ -80,7 +80,6 @@ libN$(1)_$(2).a: $$(NGL_$(1)_$(2)_OBJ) ar rcs $$@ $$(NGL_$(1)_$(2)_OBJ) CLEAN_FILES += libFastUIDraw$(1)_$(2).a libN$(1)_$(2).a -TARGETLIST += libN$(1)_$(2)-static libFastUIDraw$(1)_$(2)-static INSTALL_STATIC_LIBS += libFastUIDraw$(1)_$(2).a libN$(1)_$(2).a endif @@ -93,7 +92,7 @@ define glrules $(eval $(call glrule,$(1),release,$(2)) $(call glrule,$(1),debug,$(2)) ifeq ($(2),1) -TARGETLIST += libFastUIDraw$(1) libFastUIDraw$(1)-static libFastUIDraw$(1)_debug libFastUIDraw$(1)_release +TARGETLIST += libFastUIDraw$(1) libFastUIDraw$(1)-static libFastUIDraw$(1): libFastUIDraw$(1)_debug libFastUIDraw$(1)_release libFastUIDraw$(1)-static: libFastUIDraw$(1)_release-static libFastUIDraw$(1)_debug-static .PHONY: libFastUIDraw$(1) @@ -101,7 +100,7 @@ libFastUIDraw$(1)-static: libFastUIDraw$(1)_release-static libFastUIDraw$(1)_deb .PHONY: libFastUIDraw$(1)_debug libN$(1): libN$(1)_debug libN$(1)_release libN$(1)-static: libN$(1)_debug-static libN$(1)_release-static -TARGETLIST += libN$(1) libN$(1)_debug libN$(1)_release libN$(1)-static +TARGETLIST += libN$(1) libN$(1)-static all: libFastUIDraw$(1)-static libFastUIDraw$(1) libN$(1) libN$(1)-static .PHONY: libN$(1) .PHONY: libN$(1)_debug diff --git a/make/Makefile.install.mk b/make/Makefile.install.mk index fc0935129..a02eb6371 100644 --- a/make/Makefile.install.mk +++ b/make/Makefile.install.mk @@ -60,7 +60,6 @@ fastuidraw$(2)-$(1).pc: fastuidraw-backend.pc.in n$(2)-$(1).pc .SECONDARY: fastuidraw$(2)-$(1).pc n$(2)-$(1).pc pkg-config-files: fastuidraw$(2)-$(1).pc n$(2)-$(1).pc INSTALL_PKG_FILES+=fastuidraw$(2)-$(1).pc n$(2)-$(1).pc -TARGETLIST+=fastuidraw$(2)-$(1).pc n$(2)-$(1).pc endif ) CLEAN_FILES+=fastuidraw$(2)-$(1).pc n$(2)-$(1).pc @@ -87,14 +86,12 @@ nEGL-$(1).pc: n.pc.in fastuidraw-$(1).pc @sed -i 's!@INSTALL_LOCATION@!$(INSTALL_LOCATION_VALUE)!g' $$@ @sed -i 's!@N_ADDITIONAL_LIBS@!-lEGL!g' $$@ INSTALL_PKG_FILES+=nEGL-$(1).pc -TARGETLIST+=nEGL-$(1).pc pkg-config-files: nEGL-$(1).pc endif .PHONY:fastuidraw-$(1).pc nEGL-$(1).pc .SECONDARY: fastuidraw-$(1).pc nEGL-$(1).pc CLEAN_FILES+=fastuidraw-$(1).pc nEGL-$(1).pc INSTALL_PKG_FILES+=fastuidraw-$(1).pc -TARGETLIST+=fastuidraw-$(1).pc pkg-config-files: fastuidraw-$(1).pc $(call pkgconfrulesapi,$(1),GL,$(BUILD_GL)) $(call pkgconfrulesapi,$(1),GLES,$(BUILD_GLES))) From 90cdcd11df31a53ae5cfdb76fc56d1785a990112 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 12:33:24 +0300 Subject: [PATCH 23/52] Makefile: more targets output cleanup Change-Id: I2d336326d7271817f6f757644d1d8588aab81151 --- make/Makefile.demo.rules.mk | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/make/Makefile.demo.rules.mk b/make/Makefile.demo.rules.mk index f6753c248..2a81ab231 100644 --- a/make/Makefile.demo.rules.mk +++ b/make/Makefile.demo.rules.mk @@ -78,7 +78,6 @@ $(1)-$(3): $(1)-$(2)-$(3) .PHONY: $(1)-$(3) $(1): $(1)-$(2) .PHONY: $(1) -DEMO_TARGETLIST += $(1)-$(2)-$(3) $(1)-$(2)-$(3): libFastUIDraw$(2)_$(3) $$(NEGL_$(3)_LIB_DEP_$(2)) $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(THISDEMO_$(1)_$(2)_$(3)_DEPS) $$(CXX) -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(DEMO_$(3)_LIBS_$(2)) endif @@ -97,6 +96,11 @@ endif ) endef +define adddemotarget +$(eval DEMO_TARGETLIST+=$(1)) +endef + +$(foreach demoname,$(DEMOS),$(call adddemotarget,$(demoname))) TARGETLIST+=demos demos-debug demos-release From 86d0190d52aa13d5cce7cc58103bf46798d84882 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 13:33:21 +0300 Subject: [PATCH 24/52] fastuidraw-config: tweaks for linking against static FastUIDraw.a Change-Id: Idc32309ea98ab547f573f94d8f4c77aac72b3f46 --- fastuidraw-config.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fastuidraw-config.in b/fastuidraw-config.in index 2b212d150..0745e506c 100644 --- a/fastuidraw-config.in +++ b/fastuidraw-config.in @@ -162,13 +162,13 @@ if [ "$print_cflags" = "1" ]; then fi if [ "$static_linking" = "1" ]; then - pre_link="-Wl,--whole-archive -Wl,-Bstatic" - post_link="-Wl,--no-whole-archive -Wl,-Bdynamic" + pre_link="-Wl,--whole-archive,-Bstatic" + post_link="-Wl,--no-whole-archive" else pre_link= post_link= fi if [ "$print_libs" = "1" ]; then - echo $pre_link $libs $post_link $base_libs + echo $base_libs $pre_link $libs $post_link fi From 039982656ec71cf215b1864ae4be846ffbb28753 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 13:38:06 +0300 Subject: [PATCH 25/52] Makefile: add demo targets that link statically --- make/Makefile.demo.rules.mk | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/make/Makefile.demo.rules.mk b/make/Makefile.demo.rules.mk index 2a81ab231..01fa67e83 100644 --- a/make/Makefile.demo.rules.mk +++ b/make/Makefile.demo.rules.mk @@ -3,9 +3,12 @@ CLEAN_FILES += $(DEMO_COMMON_RESOURCE_STRING_SRCS) # This is awful. Makes me wish I used cmake. DEMO_COMMON_LIBS := $(shell sdl2-config --libs) -lSDL2_image +DEMO_COMMON_STATIC_LIBS := $(shell sdl2-config --static-libs) -lSDL2_image ifeq ($(MINGW_BUILD),1) TEMP := $(DEMO_COMMON_LIBS) DEMO_COMMON_LIBS := $(subst -mwindows, ,$(TEMP)) + TEMP := $(DEMO_COMMON_STATIC_LIBS) + DEMO_COMMON_STATIC_LIBS := $(subst -mwindows, ,$(TEMP)) endif DEMO_COMMON_CFLAGS = $(shell sdl2-config --cflags) -Idemos/common @@ -17,9 +20,13 @@ DEMO_debug_CFLAGS = -g $(DEMO_COMMON_CFLAGS) define demobuildrules $(eval DEMO_$(2)_CFLAGS_$(1) = $$(DEMO_$(2)_CFLAGS) $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --cflags --incdir=inc) -DEMO_$(2)_LIBS_$(1) = $(DEMO_COMMON_LIBS) $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --libs --libdir=.) +DEMO_$(2)_LIBS_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --libs --libdir=.) +DEMO_$(2)_LIBS_STATIC_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --static --libs --libdir=.) ifeq ($(MINGW_BUILD),0) -DEMO_$(2)_LIBS_$(1) += -lEGL -lwayland-egl $$(shell ./fastuidraw-config.nodir --negl --$(2) --libs --libdir=.) +DEMO_COMMON_LIBS += -lEGL -lwayland-egl +DEMO_COMMON_STATIC_LIBS += -lEGL -lwayland-egl +DEMO_$(2)_LIBS_$(1) += $$(shell ./fastuidraw-config.nodir --negl --$(2) --libs --libdir=.) +DEMO_$(2)_LIBS_STATIC_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --negl --static --libs --libdir=.) NEGL_$(2)_DEP_$(1) = $(NGL_EGL_HPP) NEGL_$(2)_LIB_DEP_$(1) = libNEGL_$(2).so endif @@ -52,7 +59,9 @@ THISDEMO_$(1)_$(2)_$(3)_OBJS_RAW = $$(patsubst %.cpp, %.o, $$(THISDEMO_$(1)_$(2) THISDEMO_$(1)_$(2)_$(3)_DEPS = $$(addprefix build/demo/$(3)/$(2)/, $$(THISDEMO_$(1)_$(2)_$(3)_DEPS_RAW)) THISDEMO_$(1)_$(2)_$(3)_OBJS = $$(addprefix build/demo/$(3)/$(2)/, $$(THISDEMO_$(1)_$(2)_$(3)_OBJS_RAW)) THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS = $$(THISDEMO_$(1)_$(2)_$(3)_OBJS) $$(THISDEMO_$(1)_$(2)_$(3)_RESOURCE_OBJS) -CLEAN_FILES += $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $(1)-$(2)-$(3) $(1)-$(2)-$(3).exe $$(THISDEMO_$(1)_RESOURCE_STRING_SRCS) +CLEAN_FILES += $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(THISDEMO_$(1)_RESOURCE_STRING_SRCS) +CLEAN_FILES += $(1)-$(2)-$(3) $(1)-$(2)-$(3).exe +CLEAN_FILES += $(1)-$(2)-$(3)-static $(1)-$(2)-$(3)-static.exe SUPER_CLEAN_FILES += $$(THISDEMO_$(1)_$(2)_$(3)_DEPS) ifeq ($(4),1) ifneq ($(MAKECMDGOALS),clean) @@ -78,8 +87,19 @@ $(1)-$(3): $(1)-$(2)-$(3) .PHONY: $(1)-$(3) $(1): $(1)-$(2) .PHONY: $(1) -$(1)-$(2)-$(3): libFastUIDraw$(2)_$(3) $$(NEGL_$(3)_LIB_DEP_$(2)) $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(THISDEMO_$(1)_$(2)_$(3)_DEPS) - $$(CXX) -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(DEMO_$(3)_LIBS_$(2)) +$(1)-$(2)-$(3): libFastUIDraw$(2)_$(3) $$(NEGL_$(3)_LIB_DEP_$(2)) $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) + $$(CXX) -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $$(DEMO_$(3)_LIBS_$(2)) $(DEMO_COMMON_LIBS) + +demos-$(2)-$(3)-static: $(1)-$(2)-$(3)-static +.PHONY: demos-$(2)-$(3)-static +$(1)-$(2)-static: $(1)-$(2)-$(3)-static +.PHONY: $(1)-$(2)-static +$(1)-$(3)-static: $(1)-$(2)-$(3)-static +.PHONY: $(1)-$(3)-static +$(1)-static: $(1)-$(2)-static +.PHONY: $(1)-static +$(1)-$(2)-$(3)-static: libFastUIDraw_$(3).a libFastUIDraw$(2)_$(3).a libN$(2)_$(3).a libNEGL_$(3).a $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) + $$(CXX) -static-libstdc++ -static-libgcc -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $(DEMO_COMMON_STATIC_LIBS) $$(DEMO_$(3)_LIBS_STATIC_$(2)) endif ) endef @@ -104,6 +124,7 @@ $(foreach demoname,$(DEMOS),$(call adddemotarget,$(demoname))) TARGETLIST+=demos demos-debug demos-release +TARGETLIST+=demos-static demos-debug-static demos-release-static # $1 --> gl or gles # $2 --> (0: skip build targets, 1: add build targets) @@ -116,6 +137,11 @@ demos-release: demos-$(1)-release demos-debug: demos-$(1)-debug .PHONY: demos-$(1) TARGETLIST += demos-$(1) +demos-$(1)-static: demos-$(1)-release-static demos-$(1)-debug-static +demos-release-static: demos-$(1)-release-static +demos-debug-static: demos-$(1)-debug-static +.PHONY: demos-$(1)-static +TARGETLIST += demos-$(1)-static endif ) endef From b033d13bfd69d6cf43ba5961ac11930071cb10ef Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 14:43:33 +0300 Subject: [PATCH 26/52] fastuidraw/painter/strokeD_path: expose directly StrokedCapsJoins and remove echoing of its functions Change-Id: Id1d9fab20dcacc4df8e758170fa8f630efd5db0f --- demos/painter_path_test/main.cpp | 4 +- inc/fastuidraw/painter/stroked_caps_joins.hpp | 3 +- inc/fastuidraw/painter/stroked_path.hpp | 143 ++---------------- src/fastuidraw/painter/painter.cpp | 39 +++-- src/fastuidraw/painter/stroked_path.cpp | 143 +----------------- 5 files changed, 47 insertions(+), 285 deletions(-) diff --git a/demos/painter_path_test/main.cpp b/demos/painter_path_test/main.cpp index 280ad0458..c194c6e58 100644 --- a/demos/painter_path_test/main.cpp +++ b/demos/painter_path_test/main.cpp @@ -1301,12 +1301,12 @@ per_path_processing(void) for(const PerPath &P : m_paths) { reference_counted_ptr tess; - reference_counted_ptr stroked; + const StrokedCapsJoins *stroked; const PainterAttributeData *data; c_array miter_points; tess = P.m_path.tessellation(-1.0f); - stroked = tess->stroked(); + stroked = &tess->stroked()->caps_joins(); data = &stroked->miter_clip_joins(); for(unsigned int J = 0, endJ = stroked->number_joins(true); J < endJ; ++J) diff --git a/inc/fastuidraw/painter/stroked_caps_joins.hpp b/inc/fastuidraw/painter/stroked_caps_joins.hpp index d66cddd57..4bf7fa66a 100644 --- a/inc/fastuidraw/painter/stroked_caps_joins.hpp +++ b/inc/fastuidraw/painter/stroked_caps_joins.hpp @@ -50,8 +50,7 @@ class DashEvaluatorBase; * compute_chunks(); the PainterAttributeData chunking for joins * and caps is the same regardless of the cap and join type. */ -class StrokedCapsJoins: - public reference_counted::non_concurrent +class StrokedCapsJoins:noncopyable { public: /*! diff --git a/inc/fastuidraw/painter/stroked_path.hpp b/inc/fastuidraw/painter/stroked_path.hpp index 952c07a04..98796322d 100644 --- a/inc/fastuidraw/painter/stroked_path.hpp +++ b/inc/fastuidraw/painter/stroked_path.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace fastuidraw { @@ -93,46 +94,28 @@ class StrokedPath: c_array edge_chunks(void) const; - /*! - * The list of chunks to take from any of StrokedPath::bevel_joins(), - * StrokedPath::miter_clip_joins(), StrokedPath::miter_bevel_joins(), - * StrokedPath::miter_joins() or StrokedPath::rounded_joins() that - * have visible content. - */ - c_array - join_chunks(void) const; - - /*! - * The list of chunks to take from any of StrokedPath::square_caps(), - * StrokedPath::adjustable_caps() or StrokedPath::rounded_caps() - * that have visible content. - */ - c_array - cap_chunks(void) const; - private: friend class StrokedPath; void *m_d; }; /*! - * Enumeration to select the chunk of all joins or edges - * of the closing edges or non-closing edges of a - * StrokedPath. + * Enumeration to select the chunk of all edges of the closing + * edges or all edges of the non-closing edges of a StrokedPath. */ enum chunk_selection { /*! - * Select the chunk that holds all the joins/edges - * of ONLY the non-closing edges of the StrokedPath + * Select the chunk that holds all the edges of + * ONLY the non-closing edges of the StrokedPath */ - all_non_closing, + all_non_closing = StrokedCapsJoins::all_non_closing, /*! - * Select the chunk that holds all the joins/edges - * of ONLY the closing edges of the StrokedPath + * Select the chunk that holds all the edges of + * ONLY the closing edges of the StrokedPath */ - all_closing, + all_closing = StrokedCapsJoins::all_closing, }; /*! @@ -151,10 +134,6 @@ class StrokedPath: * coordinates, compute what chunks are not completely * culled by the clip equations. * \param scratch_space scratch space for computations - * \param dash_evaluator if doing dashed stroking, the dash evalulator will cull - * joins not to be drawn, if nullptr only those joins not in the - * visible area defined by clip_equations are culled. - * \param dash_data data to pass to dast evaluator * \param clip_equations array of clip equations * \param clip_matrix_local 3x3 transformation from local (x, y, 1) * coordinates to clip coordinates. @@ -177,8 +156,6 @@ class StrokedPath: */ void compute_chunks(ScratchSpace &scratch_space, - const DashEvaluatorBase *dash_evaluator, - const PainterShaderData::DataBase *dash_data, c_array clip_equations, const float3x3 &clip_matrix_local, const vec2 &recip_dimensions, @@ -187,39 +164,8 @@ class StrokedPath: bool include_closing_edges, unsigned int max_attribute_cnt, unsigned int max_index_cnt, - bool take_joins_outside_of_region, ChunkSet &dst) const; - /*! - * Returns the number of joins of the StrokedPath - * \param include_joins_of_closing_edge if false disclude from the count, - * this joins of the closing edges - */ - unsigned int - number_joins(bool include_joins_of_closing_edge) const; - - /*! - * Returns a chunk value for Painter::attribute_data_chunk() - * and related calls to feed the return value to any of - * bevel_joins(), miter_clip_joins(), miter_bevel_joins(), - * miter_joins() or rounded_joins() to fetch the chunk - * of the named join. - * \param J join ID with 0 <= J < number_joins(true) - */ - unsigned int - join_chunk(unsigned int J) const; - - /*! - * Return the chunk to feed to any of bevel_joins(), - * miter_clip_joins(), miter_bevel_joins(), - * miter_joins() or rounded_joins() that holds all - * the joins of the closing edges or all the joins - * of the non-closing edges. - * \param c select joins of closing or non-closing edges - */ - unsigned int - chunk_of_joins(enum chunk_selection c) const; - /*! * Returns the data to draw the edges of a stroked path. */ @@ -236,73 +182,12 @@ class StrokedPath: chunk_of_edges(enum chunk_selection c) const; /*! - * Return the chunk to feed any of square_caps(), - * adjustable_caps() or rounded_caps() that holds - * data for all caps of this StrokedPath. + * Returns the StrokedCapsJoins of the StrokedPath that + * provides the attribute data for teh stroking of the + * joins and caps. */ - unsigned int - chunk_of_caps(void) const; - - /*! - * Returns the data to draw the square caps of a stroked path. - */ - const PainterAttributeData& - square_caps(void) const; - - /*! - * Returns the data to draw the caps of a stroked path used - * when stroking with a dash pattern. - */ - const PainterAttributeData& - adjustable_caps(void) const; - - /*! - * Returns the data to draw the bevel joins of a stroked path. - */ - const PainterAttributeData& - bevel_joins(void) const; - - /*! - * Returns the data to draw the miter joins of a stroked path, - * if the miter-limit is exceeded on stroking, the miter-join - * is clipped to the miter-limit. - */ - const PainterAttributeData& - miter_clip_joins(void) const; - - /*! - * Returns the data to draw the miter joins of a stroked path, - * if the miter-limit is exceeded on stroking, the miter-join - * is to be drawn as a bevel join. - */ - const PainterAttributeData& - miter_bevel_joins(void) const; - - /*! - * Returns the data to draw the miter joins of a stroked path, - * if the miter-limit is exceeded on stroking, the miter-join - * end point is clamped to the miter-distance. - */ - const PainterAttributeData& - miter_joins(void) const; - - /*! - * Returns the data to draw rounded joins of a stroked path. - * \param thresh will return rounded joins so that the distance - * between the approximation of the round and the - * actual round is no more than thresh. - */ - const PainterAttributeData& - rounded_joins(float thresh) const; - - /*! - * Returns the data to draw rounded caps of a stroked path. - * \param thresh will return rounded caps so that the distance - * between the approximation of the round and the - * actual round is no more than thresh. - */ - const PainterAttributeData& - rounded_caps(float thresh) const; + const StrokedCapsJoins& + caps_joins(void) const; private: void *m_d; diff --git a/src/fastuidraw/painter/painter.cpp b/src/fastuidraw/painter/painter.cpp index d9bb02299..ec81122b2 100644 --- a/src/fastuidraw/painter/painter.cpp +++ b/src/fastuidraw/painter/painter.cpp @@ -638,6 +638,8 @@ namespace std::vector m_stroke_index_adjusts; fastuidraw::StrokedPath::ChunkSet m_stroke_chunk_set; fastuidraw::StrokedPath::ScratchSpace m_stroked_path_scratch; + fastuidraw::StrokedCapsJoins::ChunkSet m_stroke_caps_joins_chunk_set; + fastuidraw::StrokedCapsJoins::ScratchSpace m_stroked_caps_joins_scratch; // common filling work room WindingSet m_fill_ws; @@ -1834,6 +1836,7 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, const PainterAttributeData *edge_data(nullptr), *cap_data(nullptr), *join_data(nullptr); bool is_miter_join; const PainterShaderData::DataBase *raw_data; + const StrokedCapsJoins &caps_joins(path.caps_joins()); raw_data = draw.m_item_shader_data.data().data_base(); edge_data = &path.edges(); @@ -1842,11 +1845,11 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, switch(cp) { case PainterEnums::rounded_caps: - cap_data = &path.rounded_caps(thresh); + cap_data = &caps_joins.rounded_caps(thresh); break; case PainterEnums::square_caps: - cap_data = &path.square_caps(); + cap_data = &caps_joins.square_caps(); break; case PainterEnums::flat_caps: @@ -1854,7 +1857,7 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, break; case PainterEnums::number_cap_styles: - cap_data = &path.adjustable_caps(); + cap_data = &caps_joins.adjustable_caps(); break; } } @@ -1863,27 +1866,27 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, { case PainterEnums::miter_clip_joins: is_miter_join = true; - join_data = &path.miter_clip_joins(); + join_data = &caps_joins.miter_clip_joins(); break; case PainterEnums::miter_bevel_joins: is_miter_join = true; - join_data = &path.miter_bevel_joins(); + join_data = &caps_joins.miter_bevel_joins(); break; case PainterEnums::miter_joins: is_miter_join = true; - join_data = &path.miter_joins(); + join_data = &caps_joins.miter_joins(); break; case PainterEnums::bevel_joins: is_miter_join = false; - join_data = &path.bevel_joins(); + join_data = &caps_joins.bevel_joins(); break; case PainterEnums::rounded_joins: is_miter_join = false; - join_data = &path.rounded_joins(thresh); + join_data = &caps_joins.rounded_joins(thresh); break; default: @@ -1893,8 +1896,8 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, float pixels_additional_room(0.0f), item_space_additional_room(0.0f); shader.stroking_data_selector()->stroking_distances(raw_data, &pixels_additional_room, &item_space_additional_room); + path.compute_chunks(d->m_work_room.m_stroked_path_scratch, - dash_evaluator, draw.m_item_shader_data.data().data_base(), d->m_clip_store.current(), d->m_clip_rect_state.item_matrix(), d->m_one_pixel_width, @@ -1903,13 +1906,25 @@ stroke_path_common(const PainterStrokeShader &shader, const PainterData &draw, close_contours, d->m_max_attribs_per_block, d->m_max_indices_per_block, - is_miter_join, d->m_work_room.m_stroke_chunk_set); + caps_joins.compute_chunks(d->m_work_room.m_stroked_caps_joins_scratch, + dash_evaluator, draw.m_item_shader_data.data().data_base(), + d->m_clip_store.current(), + d->m_clip_rect_state.item_matrix(), + d->m_one_pixel_width, + pixels_additional_room, + item_space_additional_room, + close_contours, + d->m_max_attribs_per_block, + d->m_max_indices_per_block, + is_miter_join, + d->m_work_room.m_stroke_caps_joins_chunk_set); + stroke_path(shader, draw, edge_data, d->m_work_room.m_stroke_chunk_set.edge_chunks(), - cap_data, d->m_work_room.m_stroke_chunk_set.cap_chunks(), - join_data, d->m_work_room.m_stroke_chunk_set.join_chunks(), + cap_data, d->m_work_room.m_stroke_caps_joins_chunk_set.cap_chunks(), + join_data, d->m_work_room.m_stroke_caps_joins_chunk_set.join_chunks(), with_anti_aliasing, call_back); } diff --git a/src/fastuidraw/painter/stroked_path.cpp b/src/fastuidraw/painter/stroked_path.cpp index b63725c9e..6c729ff9f 100644 --- a/src/fastuidraw/painter/stroked_path.cpp +++ b/src/fastuidraw/painter/stroked_path.cpp @@ -250,7 +250,6 @@ namespace fastuidraw::vecN, 2> m_clip_scratch_vec2s; std::vector m_clip_scratch_floats; - fastuidraw::StrokedCapsJoins::ScratchSpace m_caps_joins; }; class EdgeRanges @@ -1605,24 +1604,6 @@ edge_chunks(void) const return d->edge_chunks(); } -fastuidraw::c_array -fastuidraw::StrokedPath::ChunkSet:: -join_chunks(void) const -{ - ChunkSetPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.join_chunks(); -} - -fastuidraw::c_array -fastuidraw::StrokedPath::ChunkSet:: -cap_chunks(void) const -{ - ChunkSetPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.cap_chunks(); -} - ////////////////////////////////////////////////////////////// // fastuidraw::StrokedPath methods fastuidraw::StrokedPath:: @@ -1645,8 +1626,6 @@ fastuidraw::StrokedPath:: void fastuidraw::StrokedPath:: compute_chunks(ScratchSpace &scratch_space, - const DashEvaluatorBase *dash_evaluator, - const PainterShaderData::DataBase *dash_data, c_array clip_equations, const float3x3 &clip_matrix_local, const vec2 &recip_dimensions, @@ -1655,7 +1634,6 @@ compute_chunks(ScratchSpace &scratch_space, bool include_closing_edges, unsigned int max_attribute_cnt, unsigned int max_index_cnt, - bool take_joins_outside_of_region, ChunkSet &dst) const { StrokedPathPrivate *d; @@ -1666,19 +1644,6 @@ compute_chunks(ScratchSpace &scratch_space, scratch_space_ptr = static_cast(scratch_space.m_d); chunk_set_ptr = static_cast(dst.m_d); - d->m_caps_joins.compute_chunks(scratch_space_ptr->m_caps_joins, - dash_evaluator, dash_data, - clip_equations, - clip_matrix_local, - recip_dimensions, - pixels_additional_room, - item_space_additional_room, - include_closing_edges, - max_attribute_cnt, - max_index_cnt, - take_joins_outside_of_region, - chunk_set_ptr->m_caps_joins); - if (d->m_empty_path) { chunk_set_ptr->reset(); @@ -1715,113 +1680,11 @@ chunk_of_edges(enum chunk_selection c) const return d->m_chunk_of_edges[c]; } -unsigned int -fastuidraw::StrokedPath:: -number_joins(bool include_joins_of_closing_edge) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.number_joins(include_joins_of_closing_edge); -} - -unsigned int -fastuidraw::StrokedPath:: -join_chunk(unsigned int J) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.join_chunk(J); -} - -unsigned int -fastuidraw::StrokedPath:: -chunk_of_joins(enum chunk_selection c) const -{ - StrokedPathPrivate *d; - enum StrokedCapsJoins::chunk_selection cc; - - d = static_cast(m_d); - cc = static_cast(c); - return d->m_caps_joins.chunk_of_joins(cc); -} - -unsigned int -fastuidraw::StrokedPath:: -chunk_of_caps(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.chunk_of_caps(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -square_caps(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.square_caps(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -adjustable_caps(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.adjustable_caps(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -bevel_joins(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.bevel_joins(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -miter_clip_joins(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.miter_clip_joins(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -miter_bevel_joins(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.miter_bevel_joins(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -miter_joins(void) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.miter_joins(); -} - -const fastuidraw::PainterAttributeData& -fastuidraw::StrokedPath:: -rounded_joins(float thresh) const -{ - StrokedPathPrivate *d; - d = static_cast(m_d); - return d->m_caps_joins.rounded_joins(thresh); -} - -const fastuidraw::PainterAttributeData& +const fastuidraw::StrokedCapsJoins& fastuidraw::StrokedPath:: -rounded_caps(float thresh) const +caps_joins(void) const { StrokedPathPrivate *d; d = static_cast(m_d); - return d->m_caps_joins.rounded_caps(thresh); + return d->m_caps_joins; } From dfa336ed11a8153cc8fff1f6a44967ea7b7a8438 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 14:52:55 +0300 Subject: [PATCH 27/52] Makefile/fastuidraw-config: tweaks to static libs linking flags Change-Id: I7ac21ad445f66abcdd1ebe790a438d2225488ab3 --- fastuidraw-config.in | 2 +- make/Makefile.demo.rules.mk | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/fastuidraw-config.in b/fastuidraw-config.in index 0745e506c..4cb0de360 100644 --- a/fastuidraw-config.in +++ b/fastuidraw-config.in @@ -163,7 +163,7 @@ fi if [ "$static_linking" = "1" ]; then pre_link="-Wl,--whole-archive,-Bstatic" - post_link="-Wl,--no-whole-archive" + post_link="-Wl,--no-whole-archive -static-libstdc++ -static-libgcc" else pre_link= post_link= diff --git a/make/Makefile.demo.rules.mk b/make/Makefile.demo.rules.mk index 01fa67e83..cc12a0546 100644 --- a/make/Makefile.demo.rules.mk +++ b/make/Makefile.demo.rules.mk @@ -3,12 +3,9 @@ CLEAN_FILES += $(DEMO_COMMON_RESOURCE_STRING_SRCS) # This is awful. Makes me wish I used cmake. DEMO_COMMON_LIBS := $(shell sdl2-config --libs) -lSDL2_image -DEMO_COMMON_STATIC_LIBS := $(shell sdl2-config --static-libs) -lSDL2_image ifeq ($(MINGW_BUILD),1) TEMP := $(DEMO_COMMON_LIBS) DEMO_COMMON_LIBS := $(subst -mwindows, ,$(TEMP)) - TEMP := $(DEMO_COMMON_STATIC_LIBS) - DEMO_COMMON_STATIC_LIBS := $(subst -mwindows, ,$(TEMP)) endif DEMO_COMMON_CFLAGS = $(shell sdl2-config --cflags) -Idemos/common @@ -24,7 +21,6 @@ DEMO_$(2)_LIBS_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --libs -- DEMO_$(2)_LIBS_STATIC_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --static --libs --libdir=.) ifeq ($(MINGW_BUILD),0) DEMO_COMMON_LIBS += -lEGL -lwayland-egl -DEMO_COMMON_STATIC_LIBS += -lEGL -lwayland-egl DEMO_$(2)_LIBS_$(1) += $$(shell ./fastuidraw-config.nodir --negl --$(2) --libs --libdir=.) DEMO_$(2)_LIBS_STATIC_$(1) = $$(shell ./fastuidraw-config.nodir --$(1) --$(2) --negl --static --libs --libdir=.) NEGL_$(2)_DEP_$(1) = $(NGL_EGL_HPP) @@ -99,7 +95,7 @@ $(1)-$(3)-static: $(1)-$(2)-$(3)-static $(1)-static: $(1)-$(2)-static .PHONY: $(1)-static $(1)-$(2)-$(3)-static: libFastUIDraw_$(3).a libFastUIDraw$(2)_$(3).a libN$(2)_$(3).a libNEGL_$(3).a $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) - $$(CXX) -static-libstdc++ -static-libgcc -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $(DEMO_COMMON_STATIC_LIBS) $$(DEMO_$(3)_LIBS_STATIC_$(2)) + $$(CXX) -o $$@ $$(THISDEMO_$(1)_$(2)_$(3)_ALL_OBJS) $(DEMO_COMMON_LIBS) $$(DEMO_$(3)_LIBS_STATIC_$(2)) endif ) endef From b0b021edd9ac70a2273eadcca14fe6f8291e735e Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 15:19:18 +0300 Subject: [PATCH 28/52] Makefile: tweaks to static lib options and internal labels of Makefile Change-Id: I54fa4f0f6a6c82f4a4b4658042355660806ae11c --- fastuidraw-config.in | 5 +++-- make/Makefile.base.lib.mk | 8 ++++---- make/Makefile.gl_backend.lib.mk | 11 ++++------- make/Makefile.install.mk | 3 ++- make/Makefile.settings.mk | 5 ++--- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/fastuidraw-config.in b/fastuidraw-config.in index 4cb0de360..af8775528 100644 --- a/fastuidraw-config.in +++ b/fastuidraw-config.in @@ -124,7 +124,6 @@ if [ "$print_cflags" = "1" ] || [ "$print_libs" = "1" ]; then fi fi -base_libs="@FASTUIDRAW_LIBS@" libs="$dir_libs -lFastUIDraw_$mode" cflags="$base_cflags" @@ -164,11 +163,13 @@ fi if [ "$static_linking" = "1" ]; then pre_link="-Wl,--whole-archive,-Bstatic" post_link="-Wl,--no-whole-archive -static-libstdc++ -static-libgcc" + base_libs="@FASTUIDRAW_DEPS_STATIC_LIBS@" else pre_link= post_link= + base_libs="@FASTUIDRAW_DEPS_LIBS@" fi if [ "$print_libs" = "1" ]; then - echo $base_libs $pre_link $libs $post_link + echo $base_libs $pre_link $libs $post_link fi diff --git a/make/Makefile.base.lib.mk b/make/Makefile.base.lib.mk index b2a69d7cb..5693058b3 100644 --- a/make/Makefile.base.lib.mk +++ b/make/Makefile.base.lib.mk @@ -1,4 +1,5 @@ -FASTUIDRAW_LIBS += $(shell freetype-config --libs) +FASTUIDRAW_DEPS_LIBS += $(shell freetype-config --libs) +FASTUIDRAW_DEPS_STATIC_LIBS += $(shell freetype-config --static --libs) FASTUIDRAW_BASE_CFLAGS = -std=c++11 -D_USE_MATH_DEFINES FASTUIDRAW_debug_BASE_CFLAGS = $(FASTUIDRAW_BASE_CFLAGS) -DFASTUIDRAW_DEBUG @@ -35,7 +36,6 @@ FASTUIDRAW_$(1)_RESOURCE_OBJS = $$(patsubst %.resource_string, build/$(1)/%.reso FASTUIDRAW_$(1)_ALL_OBJS = $$(FASTUIDRAW_$(1)_OBJS) $$(FASTUIDRAW_PRIVATE_$(1)_OBJS) $$(FASTUIDRAW_$(1)_RESOURCE_OBJS) COMPILE_$(1)_CFLAGS=$$(FASTUIDRAW_BUILD_$(1)_FLAGS) $(FASTUIDRAW_BUILD_WARN_FLAGS) $(FASTUIDRAW_BUILD_INCLUDES_CFLAGS) $$(FASTUIDRAW_$(1)_CFLAGS) CLEAN_FILES += $$(FASTUIDRAW_$(1)_ALL_OBJS) $$(FASTUIDRAW_$(1)_RESOURCE_OBJS) -FASTUIDRAW_$(1)_LIBS = -lFastUIDraw_$(1) $(FASTUIDRAW_LIBS) SUPER_CLEAN_FILES += $$(FASTUIDRAW_$(1)_DEPS) build/$(1)/%.resource_string.o: build/string_resources_cpp/%.resource_string.cpp @mkdir -p $$(dir $$@) @@ -61,7 +61,7 @@ ifeq ($(MINGW_BUILD),1) libFastUIDraw_$(1): libFastUIDraw_$(1).dll libFastUIDraw_$(1).dll.a: libFastUIDraw_$(1).dll libFastUIDraw_$(1).dll: $$(FASTUIDRAW_$(1)_ALL_OBJS) - $(CXX) -shared -Wl,--out-implib,libFastUIDraw_$(1).dll.a -o libFastUIDraw_$(1).dll $$(FASTUIDRAW_$(1)_ALL_OBJS) $(FASTUIDRAW_LIBS) + $(CXX) -shared -Wl,--out-implib,libFastUIDraw_$(1).dll.a -o libFastUIDraw_$(1).dll $$(FASTUIDRAW_$(1)_ALL_OBJS) $(FASTUIDRAW_DEPS_LIBS) CLEAN_FILES += libFastUIDraw_$(1).dll libFastUIDraw_$(1).dll.a INSTALL_LIBS += libFastUIDraw_$(1).dll.a INSTALL_EXES += libFastUIDraw_$(1).dll @@ -70,7 +70,7 @@ else libFastUIDraw_$(1): libFastUIDraw_$(1).so libFastUIDraw_$(1).so: $(FASTUIDRAW_STRING_RESOURCES_SRCS) $$(FASTUIDRAW_$(1)_ALL_OBJS) - $(CXX) -shared -Wl,-soname,libFastUIDraw_$(1).so -o libFastUIDraw_$(1).so $$(FASTUIDRAW_$(1)_ALL_OBJS) $(FASTUIDRAW_LIBS) + $(CXX) -shared -Wl,-soname,libFastUIDraw_$(1).so -o libFastUIDraw_$(1).so $$(FASTUIDRAW_$(1)_ALL_OBJS) $(FASTUIDRAW_DEPS_LIBS) CLEAN_FILES += libFastUIDraw_$(1).so INSTALL_LIBS += libFastUIDraw_$(1).so .PHONY: libFastUIDraw_$(1) libFastUIDraw diff --git a/make/Makefile.gl_backend.lib.mk b/make/Makefile.gl_backend.lib.mk index c14de5dff..d4632b354 100644 --- a/make/Makefile.gl_backend.lib.mk +++ b/make/Makefile.gl_backend.lib.mk @@ -1,7 +1,5 @@ FASTUIDRAW_GL_CFLAGS = FASTUIDRAW_GLES_CFLAGS = -DFASTUIDRAW_GL_USE_GLES -FASTUIDRAW_GL_LIBS = -FASTUIDRAW_GLES_LIBS = FASTUIDRAW_GL_STRING_RESOURCES_SRCS = $(patsubst %.resource_string, build/string_resources_cpp/%.resource_string.cpp, $(FASTUIDRAW_GL_RESOURCE_STRING) ) CLEAN_FILES += $(FASTUIDRAW_GL_STRING_RESOURCES_SRCS) @@ -39,7 +37,6 @@ NGL_$(1)_$(2)_OBJ = $$(patsubst %.cpp, build/$(2)/$(1)/%.o, $$(NGL_$(1)_SRCS)) FASTUIDRAW_$(1)_$(2)_DEPS = $$(patsubst %.cpp, build/$(2)/$(1)/%.d, $$(FASTUIDRAW_GL_SOURCES)) FASTUIDRAW_$(1)_$(2)_RESOURCE_OBJS = $$(patsubst %.resource_string, build/$(2)/$(1)/%.resource_string.o, $$(FASTUIDRAW_GL_RESOURCE_STRING)) FASTUIDRAW_$(1)_$(2)_ALL_OBJS = $$(FASTUIDRAW_$(1)_$(2)_OBJS) $$(FASTUIDRAW_$(1)_$(2)_PRIVATE_OBJS) $$(FASTUIDRAW_$(1)_$(2)_RESOURCE_OBJS) -FASTUIDRAW_$(1)_$(2)_LIBS = -lFastUIDraw$(1)_$(2) -lN$(1)_$(2) $$(FASTUIDRAW_$(2)_LIBS) $$(FASTUIDRAW_$(1)_LIBS) CLEAN_FILES += $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) SUPER_CLEAN_FILES += $$(FASTUIDRAW_$(1)_$(2)_DEPS) $$(FASTUIDRAW_$(1)_$(2)_DEPS) $$(NGL_$(1)_$(2)_OBJ) CLEAN_FILES += libFastUIDraw$(1)_$(2).dll libFastUIDraw$(1)_$(2).dll.a libN$(1)_$(2).dll libN$(1)_$(2).dll.a @@ -52,20 +49,20 @@ ifeq ($(MINGW_BUILD),1) libFastUIDraw$(1)_$(2): libFastUIDraw$(1)_$(2).dll libFastUIDraw$(1)_$(2).dll.a: libFastUIDraw$(1)_$(2).dll libFastUIDraw$(1)_$(2).dll: libFastUIDraw_$(2).dll libN$(1)_$(2).dll $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) - $(CXX) -shared -Wl,--out-implib,libFastUIDraw$(1)_$(2).dll.a -o libFastUIDraw$(1)_$(2).dll $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) $$(FASTUIDRAW_$(2)_LIBS) -L. -lN$(1)_$(2) + $(CXX) -shared -Wl,--out-implib,libFastUIDraw$(1)_$(2).dll.a -o libFastUIDraw$(1)_$(2).dll $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) -L. -lN$(1)_$(2) -lFastUIDraw_$(2) libN$(1)_$(2): libN$(1)_$(2).dll.a libN$(1)_$(2).dll.a: libN$(1)_$(2).dll libN$(1)_$(2).dll: $$(NGL_$(1)_$(2)_OBJ) libFastUIDraw_$(2) - $(CXX) -shared -Wl,--out-implib,libN$(1)_$(2).dll.a -o libN$(1)_$(2).dll $$(NGL_$(1)_$(2)_OBJ) -L. $$(FASTUIDRAW_$(2)_LIBS) + $(CXX) -shared -Wl,--out-implib,libN$(1)_$(2).dll.a -o libN$(1)_$(2).dll $$(NGL_$(1)_$(2)_OBJ) -L. -lFastUIDraw_$(2) INSTALL_LIBS += libFastUIDraw$(1)_$(2).dll.a libN$(1)_$(2).dll.a INSTALL_EXES += libFastUIDraw$(1)_$(2).dll libN$(1)_$(2).dll else libFastUIDraw$(1)_$(2): libFastUIDraw$(1)_$(2).so libFastUIDraw$(1)_$(2).so: libFastUIDraw_$(2).so libN$(1)_$(2).so $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) - $(CXX) -shared -Wl,-soname,libFastUIDraw$(1)_$(2).so -o libFastUIDraw$(1)_$(2).so $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) $$(FASTUIDRAW_$(2)_LIBS) -L. -lN$(1)_$(2) + $(CXX) -shared -Wl,-soname,libFastUIDraw$(1)_$(2).so -o libFastUIDraw$(1)_$(2).so $$(FASTUIDRAW_$(1)_$(2)_ALL_OBJS) -L. -lN$(1)_$(2) -lFastUIDraw_$(2) libN$(1)_$(2): libN$(1)_$(2).so libN$(1)_$(2).so: $$(NGL_$(1)_$(2)_OBJ) libFastUIDraw_$(2) - $(CXX) -shared -Wl,-soname,libN$(1)_$(2).so -o libN$(1)_$(2).so $$(NGL_$(1)_$(2)_OBJ) -L. $$(FASTUIDRAW_$(2)_LIBS) + $(CXX) -shared -Wl,-soname,libN$(1)_$(2).so -o libN$(1)_$(2).so $$(NGL_$(1)_$(2)_OBJ) -L. -lFastUIDraw_$(2) INSTALL_LIBS += libFastUIDraw$(1)_$(2).so libN$(1)_$(2).so endif diff --git a/make/Makefile.install.mk b/make/Makefile.install.mk index a02eb6371..e4b39077b 100644 --- a/make/Makefile.install.mk +++ b/make/Makefile.install.mk @@ -9,7 +9,8 @@ OTHER_TYPE_debug = release fastuidraw-config.nodir: fastuidraw-config.in @echo Generating $@ @cp $< $@ - @sed -i 's!@FASTUIDRAW_LIBS@!$(FASTUIDRAW_LIBS)!g' $@ + @sed -i 's!@FASTUIDRAW_DEPS_LIBS@!$(FASTUIDRAW_DEPS_LIBS)!g' $@ + @sed -i 's!@FASTUIDRAW_DEPS_STATIC_LIBS@!$(FASTUIDRAW_DEPS_STATIC_LIBS)!g' $@ @sed -i 's!@FASTUIDRAW_release_CFLAGS@!$(FASTUIDRAW_release_CFLAGS)!g' $@ @sed -i 's!@FASTUIDRAW_debug_CFLAGS@!$(FASTUIDRAW_debug_CFLAGS)!g' $@ @sed -i 's!@FASTUIDRAW_GLES_CFLAGS@!$(FASTUIDRAW_GLES_CFLAGS)!g' $@ diff --git a/make/Makefile.settings.mk b/make/Makefile.settings.mk index 6715169f6..db8ac8ddc 100644 --- a/make/Makefile.settings.mk +++ b/make/Makefile.settings.mk @@ -21,13 +21,12 @@ DARWIN_BUILD = 0 CXX ?= g++ CC ?= gcc STRING_RESOURCE_CC = shell_scripts/fastuidraw-create-resource-cpp-file.sh -FASTUIDRAW_LIBS = - ####################################### # Platform specific libraries needed ifeq ($(MINGW_BUILD),1) - FASTUIDRAW_LIBS += -lmingw32 + FASTUIDRAW_DEPS_LIBS += -lmingw32 + FASTUIDRAW_DEPS_STATIC_LIBS += -lmingw32 endif ############################################# From c4913f7ec656b62a5c0344bc89954f0022a3d928 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 15:21:17 +0300 Subject: [PATCH 29/52] fastuidraw-config: on --help, print --static option Change-Id: I895c6d4078aac76e0e6ef3a5e77e952aed24c42b --- fastuidraw-config.in | 1 + 1 file changed, 1 insertion(+) diff --git a/fastuidraw-config.in b/fastuidraw-config.in index af8775528..041432058 100644 --- a/fastuidraw-config.in +++ b/fastuidraw-config.in @@ -6,6 +6,7 @@ print_help() { echo " --debug: indicate to compile/link for debug" echo " --cflags: print compile flags" echo " --libs: print link flags" + echo " --static: modifier to indicate statically linking against FastUIDraw" echo " --nodirs: exclude directory directives of FastUIDraw install location" echo " --libdir=/some/path: specify library directory" echo " --incdir=/some/path: specify include directory" From d123babe083fb1f7d26321a76398bae2de17980a Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 16:25:55 +0300 Subject: [PATCH 30/52] fastuidraw/tessellated_path: remove threshhold type (since there is only one type) Change-Id: I5b1007a6014551ae2562d9327d0264a82fee9b6b --- inc/fastuidraw/path.hpp | 33 ++--- inc/fastuidraw/tessellated_path.hpp | 65 +--------- src/fastuidraw/painter/painter.cpp | 4 +- src/fastuidraw/path.cpp | 183 +++++++++------------------- src/fastuidraw/tessellated_path.cpp | 18 ++- 5 files changed, 87 insertions(+), 216 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index ab7dbb356..5b1160ae2 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -108,16 +108,15 @@ class PathContour: * * \param tess_params tessellation parameters * \param out_data location to which to write the edge tessellated - * \param out_threshholds location to which to write the threshholds - * the tessellation achieved; array is indexed - * by \ref TessellatedPath::threshhold_type_t. - * An implementation MUST write to EACH entry. + * \param out_threshhold location to which to write an upperbound for the + * distance between the curve and the tesseallation + * approximation. */ virtual unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const = 0; + float *out_threshhold) const = 0; /*! * To be implemented by a derived class to return a fast (and approximate) @@ -170,7 +169,7 @@ class PathContour: unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const; + float *out_threshholds) const; virtual void approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const; @@ -216,7 +215,7 @@ class PathContour: unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const; + float *out_threshholds) const; /*! * To be implemented by a derived to assist in recursive tessellation. @@ -227,20 +226,15 @@ class PathContour: * \param out_p location to which to write the position of the point * on the curve in the middle (with repsect to time) of * in_region - * \param out_threshholds location to which to write the threshholds - * the tessellation achieved; array is indexed - * by \ref TessellatedPath::threshhold_type_t. - * An implementation MUST write to the index - * \ref TessellatedPath::threshhold_curve_distance. - * For all other values, if a value is negative, - * FastUIDraw will use the data from out_data - * to estimate the threshhold achieved. + * \param out_threshhold location to which to write an upperbound for the + * distance between the curve and the tesseallation + * approximation. */ virtual void tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - vec2 *out_p, c_array out_threshholds) const = 0; + vec2 *out_p, float *out_threshholds) const = 0; }; /*! @@ -290,7 +284,7 @@ class PathContour: void tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - vec2 *out_p, c_array out_threshholds) const; + vec2 *out_p, float *out_threshholds) const; virtual void approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const; @@ -355,7 +349,7 @@ class PathContour: unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const; + float *out_threshholds) const; private: arc(const arc &q, const reference_counted_ptr &prev); @@ -904,8 +898,7 @@ class Path * \param tp the type of threshhold to use for the tessellation requirement. */ const reference_counted_ptr& - tessellation(float thresh, - enum TessellatedPath::threshhold_type_t tp = TessellatedPath::threshhold_curve_distance) const; + tessellation(float thresh) const; /*! * Provided as a conveniance, returns the starting point tessellation. diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index afcabb571..e06445462 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -40,7 +40,8 @@ class FilledPath; /*! * \brief - * A TessellatedPath represents the tessellation of a Path. + * A TessellatedPath represents the tessellation of a Path + * into line segments. * * A single contour of a TessellatedPath is constructed from * a single \ref PathContour of the source \ref Path. Each @@ -58,24 +59,6 @@ class TessellatedPath: public reference_counted::non_concurrent { public: - /*! - * \brief - * Enumeration to specify the type of threshhold - * a \ref TessellationParams is. - */ - enum threshhold_type_t - { - /*! - * Threshhold specifies how much distance is between - * line segment between from successive points of a - * tessellated edge and the sub-curve of the starting - * curve between those two points. - */ - threshhold_curve_distance, - - number_threshholds, - }; - /*! * \brief * A TessellationParams stores how finely to tessellate @@ -88,7 +71,6 @@ class TessellatedPath: * Ctor, initializes values. */ TessellationParams(void): - m_threshhold_type(threshhold_curve_distance), m_threshhold(1.0f), m_max_segments(32) {} @@ -100,25 +82,10 @@ class TessellatedPath: bool operator!=(const TessellationParams &rhs) const { - return m_threshhold_type != rhs.m_threshhold_type - || m_threshhold != rhs.m_threshhold + return m_threshhold != rhs.m_threshhold || m_max_segments != rhs.m_max_segments; } - /*! - * Provided as a conveniance. Equivalent to - * \code - * m_threshhold_type = tp; - * \endcode - * \param tp value to which to assign to \ref m_threshhold_type - */ - TessellationParams& - threshhold_type(enum threshhold_type_t tp) - { - m_threshhold_type = tp; - return *this; - } - /*! * Provided as a conveniance. Equivalent to * \code @@ -133,22 +100,6 @@ class TessellatedPath: return *this; } - /*! - * Provided as a conveniance. Equivalent to - * \code - * m_threshhold_type = threshhold_curve_distance; - * m_threshhold = p; - * \endcode - * \param p value to which to assign to \ref m_threshhold - */ - TessellationParams& - curve_distance_tessellate(float p) - { - m_threshhold_type = threshhold_curve_distance; - m_threshhold = p; - return *this; - } - /*! * Set the value of \ref m_max_segments. * \param v value to which to assign to \ref m_max_segments @@ -160,15 +111,9 @@ class TessellatedPath: return *this; } - /*! - * Specifies the meaning of \ref m_threshhold. - * Default value is \ref threshhold_curve_distance. - */ - enum threshhold_type_t m_threshhold_type; - /*! * Meaning depends on \ref m_threshhold_type. - * Default value is M_PI / 30.0. + * Default value is 1.0. */ float m_threshhold; @@ -249,7 +194,7 @@ class TessellatedPath: * the named threshhold type. */ float - effective_threshhold(enum threshhold_type_t tp) const; + effective_threshhold(void) const; /*! * Returns the maximum number of segments any edge needed diff --git a/src/fastuidraw/painter/painter.cpp b/src/fastuidraw/painter/painter.cpp index ec81122b2..13e9b445a 100644 --- a/src/fastuidraw/painter/painter.cpp +++ b/src/fastuidraw/painter/painter.cpp @@ -1245,7 +1245,7 @@ select_stroked_path(const fastuidraw::Path &path, mag, m_curve_flatness); t = fastuidraw::t_min(thresh, m_curve_flatness / mag); const TessellatedPath *tess; - tess = path.tessellation(t, TessellatedPath::threshhold_curve_distance).get(); + tess = path.tessellation(t).get(); return tess->stroked().get(); } @@ -1258,7 +1258,7 @@ select_filled_path(const fastuidraw::Path &path) mag = compute_path_magnification(path); thresh = m_curve_flatness / mag; - return *path.tessellation(thresh, TessellatedPath::threshhold_curve_distance)->filled(); + return *path.tessellation(thresh)->filled(); } void diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 0168e67c1..327028c07 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -64,24 +64,23 @@ namespace unsigned int dump(fastuidraw::c_array out_data, - fastuidraw::c_array out_threshholds); + float *out_threshhold); private: void tessellation_worker(unsigned int recurse_level, fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, - fastuidraw::c_array out_threshholds); + float *out_threshhold); unsigned int fill_data(fastuidraw::c_array out_data, - fastuidraw::c_array out_threshholds); + float *out_threshhold); bool - tessellation_satsified(unsigned int recurse_level, - fastuidraw::c_array threshholds) + tessellation_satsified(unsigned int recurse_level, const float threshhold) { FASTUIDRAWunused(recurse_level); - return (threshholds[m_thresh.m_threshhold_type] < m_thresh.m_threshhold); + return (threshhold < m_thresh.m_threshhold); } void @@ -236,34 +235,23 @@ namespace typedef fastuidraw::reference_counted_ptr tessellated_path_ref; explicit - TessellatedPathList(enum fastuidraw::TessellatedPath::threshhold_type_t tp): - m_type(tp), + TessellatedPathList(void): m_done(false) {} const tessellated_path_ref& - tessellation(PathPrivate &p, float thresh); + tessellation(const fastuidraw::Path &path, float thresh); void clear(void) { - m_tesses.clear(); + m_data.clear(); m_done = false; } - void - add_tess(const tessellated_path_ref &tess); - - enum fastuidraw::TessellatedPath::threshhold_type_t - type(void) const - { - return m_type; - } - private: - enum fastuidraw::TessellatedPath::threshhold_type_t m_type; bool m_done; - std::vector m_tesses; + std::vector m_data; }; class PathPrivate:fastuidraw::noncopyable @@ -288,11 +276,8 @@ namespace void clear_tesses(void); - void - add_tess(const TessellatedPathList::tessellated_path_ref &tess); - std::vector > m_contours; - std::vector m_tesses; + TessellatedPathList m_tess_list; /* m_start_check_bb gives the index into m_contours that * have not had their bounding box absorbed into @@ -307,26 +292,18 @@ namespace class reverse_compare_thresh { public: - explicit - reverse_compare_thresh(enum fastuidraw::TessellatedPath::threshhold_type_t tp): - m_tp(tp) - {} - bool operator()(const TessellatedPathList::tessellated_path_ref &lhs, float rhs) const { - return lhs->effective_threshhold(m_tp) > rhs; + return lhs->effective_threshhold() > rhs; } bool operator()(const TessellatedPathList::tessellated_path_ref &lhs, const TessellatedPathList::tessellated_path_ref &rhs) const { - return lhs->effective_threshhold(m_tp) > rhs->effective_threshhold(m_tp); + return lhs->effective_threshhold() > rhs->effective_threshhold(); } - - private: - enum fastuidraw::TessellatedPath::threshhold_type_t m_tp; }; } @@ -335,12 +312,12 @@ namespace unsigned int Tessellator:: dump(fastuidraw::c_array out_data, - fastuidraw::c_array out_threshholds) + float *out_threshhold) { unsigned int return_value; - std::fill(out_threshholds.begin(), out_threshholds.end(), -1.0f); - return_value = fill_data(out_data, out_threshholds); + *out_threshhold = -1.0f; + return_value = fill_data(out_data, out_threshhold); out_data = out_data.sub_array(0, return_value); /* enforce start and end point values */ @@ -364,7 +341,7 @@ dump(fastuidraw::c_array out_data, unsigned int Tessellator:: fill_data(fastuidraw::c_array out_data, - fastuidraw::c_array out_threshholds) + float *out_threshhold) { /* * tessellate: note that we add the start point, then tessellate @@ -372,7 +349,7 @@ fill_data(fastuidraw::c_array out_data, * are added to m_data in order of time automatically. */ add_point(m_h->start_pt()); - tessellation_worker(0, nullptr, out_threshholds); + tessellation_worker(0, nullptr, out_threshhold); add_point(m_h->end_pt()); FASTUIDRAWassert(m_data.size() <= out_data.size()); @@ -384,7 +361,7 @@ void Tessellator:: tessellation_worker(unsigned int recurse_level, fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, - fastuidraw::c_array out_threshholds) + float *out_threshhold) { using namespace fastuidraw; @@ -392,12 +369,12 @@ tessellation_worker(unsigned int recurse_level, PathContour::interpolator_generic::tessellated_region *rgnB(nullptr); vec2 p; - m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshholds); + m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshhold); if (recurse_level + 1u < m_max_recursion - && !tessellation_satsified(recurse_level, out_threshholds)) + && !tessellation_satsified(recurse_level, *out_threshhold)) { - vecN tmpA(-1.0f), tmpB(-1.0f); + float tmpA(-1.0f), tmpB(-1.0f); /* NOTE the order of recursing and adding to m_data: * - first we recurse into the left side @@ -408,14 +385,11 @@ tessellation_worker(unsigned int recurse_level, * mid point, and all points in the right side come * after the midpoint. */ - tessellation_worker(recurse_level + 1, rgnA, tmpA); + tessellation_worker(recurse_level + 1, rgnA, &tmpA); add_point(p); - tessellation_worker(recurse_level + 1, rgnB, tmpB); + tessellation_worker(recurse_level + 1, rgnB, &tmpB); - for (unsigned int i = 0; i < TessellatedPath::number_threshholds; ++i) - { - out_threshholds[i] = t_max(tmpA[i], tmpB[i]); - } + *out_threshhold = t_max(tmpA, tmpB); } else { @@ -516,10 +490,10 @@ unsigned int fastuidraw::PathContour::interpolator_generic:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const + float *out_threshhold) const { Tessellator tesser(tess_params, this); - return tesser.dump(out_data, out_threshholds); + return tesser.dump(out_data, out_threshhold); } @@ -612,7 +586,7 @@ void fastuidraw::PathContour::bezier:: tessellate(tessellated_region *in_region, tessellated_region **out_regionA, tessellated_region **out_regionB, - vec2 *out_p, c_array out_threshholds) const + vec2 *out_p, float *out_threshhold) const { BezierPrivate *d; d = static_cast(m_d); @@ -667,9 +641,7 @@ tessellate(tessellated_region *in_region, *out_regionA = newA; *out_regionB = newB; *out_p = newA->m_pts.back(); - - out_threshholds[TessellatedPath::threshhold_curve_distance] - = t_max(newA->compute_curve_distance(), newB->compute_curve_distance()); + *out_threshhold = t_max(newA->compute_curve_distance(), newB->compute_curve_distance()); } fastuidraw::PathContour::interpolator_base* @@ -692,7 +664,7 @@ unsigned int fastuidraw::PathContour::flat:: produce_tessellation(const TessellatedPath::TessellationParams&, c_array out_data, - c_array out_threshholds) const + float *out_threshhold) const { vec2 delta(end_pt() - start_pt()); float mag(delta.magnitude()); @@ -703,7 +675,7 @@ produce_tessellation(const TessellatedPath::TessellationParams&, out_data[1].m_p = end_pt(); out_data[1].m_distance_from_edge_start = mag; - std::fill(out_threshholds.begin(), out_threshholds.end(), 0.0f); + *out_threshhold = 0.0f; return 2; } @@ -829,7 +801,7 @@ unsigned int fastuidraw::PathContour::arc:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, - c_array out_threshholds) const + float *out_threshhold) const { ArcPrivate *d; d = static_cast(m_d); @@ -853,7 +825,7 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, out_data[0].m_p = start_pt(); out_data[needed_size].m_p = end_pt(); - out_threshholds[TessellatedPath::threshhold_curve_distance] = d->m_radius * (1.0f - t_cos(delta_angle * 0.5f)); + *out_threshhold = d->m_radius * (1.0f - t_cos(delta_angle * 0.5f)); return_value = needed_size + 1; return return_value; @@ -1195,24 +1167,13 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const ///////////////////////////////// // TessellatedPathList methods -void -TessellatedPathList:: -add_tess(const tessellated_path_ref &tess) -{ - if (m_tesses.empty() - || m_tesses.back()->effective_threshhold(m_type) > tess->effective_threshhold(m_type)) - { - m_tesses.push_back(tess); - } -} - const TessellatedPathList::tessellated_path_ref& TessellatedPathList:: -tessellation(PathPrivate &path, float thresh) +tessellation(const fastuidraw::Path &path, float thresh) { using namespace fastuidraw; - if (m_tesses.empty()) + if (m_data.empty()) { TessellatedPath::TessellationParams params; vec2 bb_min, bb_max, bb_size; @@ -1221,7 +1182,7 @@ tessellation(PathPrivate &path, float thresh) * curvature; use the size of the bounding box times * 1/500 as teh default tessellation factor. */ - if (path.m_p->approximate_bounding_box(&bb_min, &bb_max)) + if (path.approximate_bounding_box(&bb_min, &bb_max)) { vec2 bb_size; float d; @@ -1229,68 +1190,65 @@ tessellation(PathPrivate &path, float thresh) d = t_max(bb_size.x(), bb_size.y()); if (d > 0.0f) { - params.curve_distance_tessellate(d / 500.0f); + params.threshhold(d / 500.0f); } } - path.add_tess(FASTUIDRAWnew TessellatedPath(*path.m_p, params)); + m_data.push_back(FASTUIDRAWnew TessellatedPath(path, params)); } - if (thresh <= 0.0 || path.m_p->is_flat()) + if (thresh <= 0.0 || path.is_flat()) { - return m_tesses.front(); + return m_data.front(); } - if (m_tesses.back()->effective_threshhold(m_type) <= thresh) + if (m_data.back()->effective_threshhold() <= thresh) { std::vector::const_iterator iter; - iter = std::lower_bound(m_tesses.begin(), - m_tesses.end(), + iter = std::lower_bound(m_data.begin(), + m_data.end(), thresh, - reverse_compare_thresh(m_type)); + reverse_compare_thresh()); - FASTUIDRAWassert(iter != m_tesses.end()); + FASTUIDRAWassert(iter != m_data.end()); FASTUIDRAWassert(*iter); - FASTUIDRAWassert((*iter)->effective_threshhold(m_type) <= thresh); + FASTUIDRAWassert((*iter)->effective_threshhold() <= thresh); return *iter; } if (m_done) { - return m_tesses.back(); + return m_data.back(); } tessellated_path_ref prev_ref, ref; TessellatedPath::TessellationParams params; - ref = m_tesses.back(); + ref = m_data.back(); params .max_segments(ref->max_segments()) - .threshhold_type(m_type) - .threshhold(ref->effective_threshhold(m_type)); + .threshhold(ref->effective_threshhold()); - while(!m_done && ref->effective_threshhold(m_type) > thresh) + while(!m_done && ref->effective_threshhold() > thresh) { params.m_threshhold *= 0.5f; while(!m_done - && ref->effective_threshhold(m_type) > params.m_threshhold) + && ref->effective_threshhold() > params.m_threshhold) { float last_tess; params.m_max_segments *= 2; - last_tess = ref->effective_threshhold(m_type); - ref = FASTUIDRAWnew TessellatedPath(*path.m_p, params); - if (last_tess > ref->effective_threshhold(m_type)) + last_tess = ref->effective_threshhold(); + ref = FASTUIDRAWnew TessellatedPath(path, params); + if (last_tess > ref->effective_threshhold()) { - path.add_tess(ref); - FASTUIDRAWassert(m_tesses.back() == ref); + m_data.push_back(ref); } else { m_done = true; /* - *std::cout << "Tapped out on type = " - * << m_type << " (max_segs = " + *std::cout << "Tapped out on type = (max_segs = " * << ref->max_segments() << ", tess_factor = " * << ref->effective_threshhold(m_type) * << ", num_points = " << ref->point_data().size() @@ -1300,7 +1258,7 @@ tessellation(PathPrivate &path, float thresh) } } - return m_tesses.back(); + return m_data.back(); } ///////////////////////////////// @@ -1311,18 +1269,12 @@ PathPrivate(fastuidraw::Path *p): m_is_flat(true), m_p(p) { - for(int i = 0; i < fastuidraw::TessellatedPath::number_threshholds; ++i) - { - enum fastuidraw::TessellatedPath::threshhold_type_t tp; - tp = static_cast(i); - m_tesses.push_back(TessellatedPathList(tp)); - } } PathPrivate:: PathPrivate(fastuidraw::Path *p, const PathPrivate &obj): m_contours(obj.m_contours), - m_tesses(obj.m_tesses), + m_tess_list(obj.m_tess_list), m_start_check_bb(obj.m_start_check_bb), m_max_bb(obj.m_max_bb), m_min_bb(obj.m_min_bb), @@ -1356,20 +1308,7 @@ void PathPrivate:: clear_tesses(void) { - for(TessellatedPathList &T : m_tesses) - { - T.clear(); - } -} - -void -PathPrivate:: -add_tess(const TessellatedPathList::tessellated_path_ref &tess) -{ - for(TessellatedPathList &T : m_tesses) - { - T.add_tess(tess); - } + m_tess_list.clear(); } ///////////////////////////////////////// @@ -1563,13 +1502,11 @@ tessellation(void) const const fastuidraw::reference_counted_ptr& fastuidraw::Path:: -tessellation(float thresh, enum TessellatedPath::threshhold_type_t tp) const +tessellation(float thresh) const { PathPrivate *d; d = static_cast(m_d); - - FASTUIDRAWassert(d->m_tesses[tp].type() == tp); - return d->m_tesses[tp].tessellation(*d, thresh); + return d->m_tess_list.tessellation(*this, thresh); } bool diff --git a/src/fastuidraw/tessellated_path.cpp b/src/fastuidraw/tessellated_path.cpp index 71459f841..7470e2f9b 100644 --- a/src/fastuidraw/tessellated_path.cpp +++ b/src/fastuidraw/tessellated_path.cpp @@ -37,7 +37,7 @@ namespace std::vector m_point_data; fastuidraw::vec2 m_box_min, m_box_max; fastuidraw::TessellatedPath::TessellationParams m_params; - fastuidraw::vecN m_effective_threshholds; + float m_effective_threshhold; unsigned int m_max_segments; fastuidraw::reference_counted_ptr m_stroked; fastuidraw::reference_counted_ptr m_filled; @@ -53,7 +53,7 @@ TessellatedPathPrivate(const fastuidraw::Path &input, m_box_min(0.0f, 0.0f), m_box_max(0.0f, 0.0f), m_params(TP), - m_effective_threshholds(0.0f), + m_effective_threshhold(0.0f), m_max_segments(0u) { using namespace fastuidraw; @@ -74,22 +74,19 @@ TessellatedPathPrivate(const fastuidraw::Path &input, for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) { unsigned int needed; - vecN tmp; + float tmp; work_room.resize(m_params.m_max_segments + 1); temp.push_back(std::vector()); needed = contour->interpolator(e)->produce_tessellation(m_params, make_c_array(work_room), - tmp); + &tmp); m_edge_ranges[o][e] = range_type(loc, loc + needed); loc += needed; FASTUIDRAWassert(needed > 0u); m_max_segments = t_max(m_max_segments, needed - 1); - for (unsigned int i = 0; i < TessellatedPath::number_threshholds; ++i) - { - m_effective_threshholds[i] = t_max(m_effective_threshholds[i], tmp[i]); - } + m_effective_threshhold = t_max(m_effective_threshhold, tmp); work_room.resize(needed); for(unsigned int n = 0; n < work_room.size(); ++n) @@ -221,12 +218,11 @@ tessellation_parameters(void) const float fastuidraw::TessellatedPath:: -effective_threshhold(enum threshhold_type_t tp) const +effective_threshhold(void) const { TessellatedPathPrivate *d; d = static_cast(m_d); - return tp < d->m_effective_threshholds.size() ? - d->m_effective_threshholds[tp] : 0.0f; + return d->m_effective_threshhold; } unsigned int From 79845216029dd9f1f0569aef5ca7db4a4cc7ccab Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 16:28:06 +0300 Subject: [PATCH 31/52] fastuidraw/tessellated_path: doxytag fixes Change-Id: I42c3fb872f21ab91755fed60f1c4eee4dadc39c2 --- inc/fastuidraw/tessellated_path.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index e06445462..dd665f364 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -112,7 +112,9 @@ class TessellatedPath: } /*! - * Meaning depends on \ref m_threshhold_type. + * The targetted threshhold, measured by an upper-bound + * (per-tessellated edge) of the distance between the line + * segments of the tessellation and the original curve. * Default value is 1.0. */ float m_threshhold; @@ -190,8 +192,7 @@ class TessellatedPath: tessellation_parameters(void) const; /*! - * Returns the tessellation threshold achieved for - * the named threshhold type. + * Returns the tessellation threshold achieved */ float effective_threshhold(void) const; From e2c32d4e0647ea90a3dd757585ed80b3cbed0def Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 16:28:56 +0300 Subject: [PATCH 32/52] fastuidraw/path: doxytag fixes Change-Id: I307c49710a329c3c7f8bd41389d919e16c1159dd --- inc/fastuidraw/path.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 5b1160ae2..e71708b6c 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -892,10 +892,9 @@ class Path * then a new TessellatedPath will be contructed on the * next call to tessellation(). * \param thresh the returned tessellated path will be so that - * TessellatedPath::curve_distance_threshhold(type) + * TessellatedPath::effective_threshhold() * is no more than thresh. A non-positive value * will return the starting point tessellation. - * \param tp the type of threshhold to use for the tessellation requirement. */ const reference_counted_ptr& tessellation(float thresh) const; From af343712970f5c9d9a7e7dd44f3653054d1ecf4e Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 10:37:58 +0300 Subject: [PATCH 33/52] fastuidraw/glsl/shaders/painter: minor fix to dashed stroking Change-Id: I6c72306296441ef1e5f61ea21eaec578833616ae --- ...w_painter_stroke.vert.glsl.resource_string | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string index faf90cd80..d2e1582dc 100644 --- a/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string +++ b/src/fastuidraw/glsl/shaders/painter/fastuidraw_painter_stroke.vert.glsl.resource_string @@ -485,8 +485,15 @@ fastuidraw_gl_vert_main(in uint sub_shader, edge. */ - if (interval_id2 == interval_id && interval_id != -1 && dash_style != fastuidraw_stroke_dashed_flat_caps) + if (interval_id2 == interval_id && interval_id != -1) { + /* since the interval ID's are the same, then the edge is completely + * contained within an interval and does not need to be extended + * regardless of caps added, also the dashing computation can + * be entirely skipped. In addition, if the interval is a "skip" + * interval, then the sub-edge is NOT drawn and we collapse it + * to a point be setting on_boundary to 0. + */ fastuidraw_stroking_dash_bits = uint(fastuidraw_stroke_gauranteed_to_be_covered_mask); fastuidraw_stroking_distance = 0.0f; if (s < 0.0) @@ -496,12 +503,19 @@ fastuidraw_gl_vert_main(in uint sub_shader, } else { + /* since the interval ID's are different, the sub-edge spans + * multiple intervals. We extend the sub-interval on the start + * and on the end by the stroking radius, but we inform the + * fragment shader of the interval boundaries closest to the + * sub-edge boundaries via fastuidraw_stroking_distance_sub_edge_start + * and fastuidraw_stroking_distance_sub_edge_end + */ fastuidraw_stroking_dash_bits = 0u; if (offset_type == fastuidraw_stroke_offset_start_sub_edge) { - float new_d, clamp_interval_end; + float clamp_interval_end; - fastuidraw_stroking_distance_sub_edge_start = (s < 0.0 )? + fastuidraw_stroking_distance_sub_edge_start = (s < 0.0) ? interval_end : d; @@ -509,18 +523,10 @@ fastuidraw_gl_vert_main(in uint sub_shader, interval_begin2 : d2; - if (s < 0.0) + if (s < 0.0 && dash_style != fastuidraw_stroke_dashed_flat_caps) { - clamp_interval_end = min(interval_end, d2); - new_d = clamp_interval_end; - - if (dash_style != fastuidraw_stroke_dashed_flat_caps) - { - new_d -= stroke_radius; - } - - position += (new_d - d) * auxiliary_offset / delta_mag; - fastuidraw_stroking_distance = new_d; + fastuidraw_stroking_distance = d - stroke_radius; + position -= auxiliary_offset * (stroke_radius / delta_mag); } else { @@ -529,7 +535,7 @@ fastuidraw_gl_vert_main(in uint sub_shader, } else { - float new_d, clamp_interval_begin; + float clamp_interval_begin; fastuidraw_stroking_distance_sub_edge_start = (s2 < 0.0) ? interval_end2 : @@ -539,24 +545,10 @@ fastuidraw_gl_vert_main(in uint sub_shader, interval_begin : d; - if (s < 0.0) + if (s < 0.0 && dash_style != fastuidraw_stroke_dashed_flat_caps) { - clamp_interval_begin = max(interval_begin, d2); - new_d = interval_begin; - - if (dash_style != fastuidraw_stroke_dashed_flat_caps) - { - new_d += stroke_radius; - } - - /* auxiliary_offset is the direction from this point - (the end of the sub-edge) to the start of the - sub-edge. This is why we have the coefficient - (d - new_d) because moving in auxiliary_offset - is moving towards the start. - */ - position += (d - new_d) * auxiliary_offset / delta_mag; - fastuidraw_stroking_distance = new_d; + fastuidraw_stroking_distance = d + stroke_radius; + position -= auxiliary_offset * (stroke_radius / delta_mag); } else { From 04db59220b1472bde5f4dfca9ba87b5a462cbb7e Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 09:06:31 +0300 Subject: [PATCH 34/52] fastuidraw/private: initialize BoundingBox min and max fields as well Change-Id: I4759a5785697c9cc45fd0152f5e2dc26e566e062 --- src/fastuidraw/private/bounding_box.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fastuidraw/private/bounding_box.hpp b/src/fastuidraw/private/bounding_box.hpp index 8c1800113..0aaae4888 100644 --- a/src/fastuidraw/private/bounding_box.hpp +++ b/src/fastuidraw/private/bounding_box.hpp @@ -33,6 +33,8 @@ namespace fastuidraw typedef vecN pt_type; BoundingBox(void): + m_min(T(0), T(0)), + m_max(T(0), T(0)), m_empty(true) {} From 8c3265663bfc762520c80efcd5846bd99be1b5f8 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 09:07:18 +0300 Subject: [PATCH 35/52] fastuidraw/tessellated_path: move distance from edge length comptuation to TessellatedPath + use BoundingBox Change-Id: I3c6ca1e51ee81f51dbb6fa75f6581c958eecd2aa --- src/fastuidraw/path.cpp | 11 --------- src/fastuidraw/tessellated_path.cpp | 36 ++++++++++++----------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 327028c07..33f29f3ce 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -324,17 +324,6 @@ dump(fastuidraw::c_array out_data, out_data.front().m_p = m_h->start_pt(); out_data.back().m_p = m_h->end_pt(); - /* compute distance values along edge */ - out_data[0].m_distance_from_edge_start = 0.0f; - for(unsigned int i = 1, endi = out_data.size(); i < endi; ++i) - { - fastuidraw::vec2 delta; - - delta = out_data[i].m_p - out_data[i-1].m_p; - out_data[i].m_distance_from_edge_start = delta.magnitude() - + out_data[i-1].m_distance_from_edge_start; - } - return return_value; } diff --git a/src/fastuidraw/tessellated_path.cpp b/src/fastuidraw/tessellated_path.cpp index 7470e2f9b..afbeb6959 100644 --- a/src/fastuidraw/tessellated_path.cpp +++ b/src/fastuidraw/tessellated_path.cpp @@ -24,6 +24,7 @@ #include #include #include "private/util_private.hpp" +#include "private/bounding_box.hpp" namespace { @@ -35,7 +36,7 @@ namespace std::vector > > m_edge_ranges; std::vector m_point_data; - fastuidraw::vec2 m_box_min, m_box_max; + fastuidraw::BoundingBox m_bounding_box; fastuidraw::TessellatedPath::TessellationParams m_params; float m_effective_threshhold; unsigned int m_max_segments; @@ -50,8 +51,6 @@ TessellatedPathPrivate:: TessellatedPathPrivate(const fastuidraw::Path &input, fastuidraw::TessellatedPath::TessellationParams TP): m_edge_ranges(input.number_contours()), - m_box_min(0.0f, 0.0f), - m_box_max(0.0f, 0.0f), m_params(TP), m_effective_threshhold(0.0f), m_max_segments(0u) @@ -91,23 +90,22 @@ TessellatedPathPrivate(const fastuidraw::Path &input, work_room.resize(needed); for(unsigned int n = 0; n < work_room.size(); ++n) { - const vec2 &pt(work_room[n].m_p); + m_bounding_box.union_point(work_room[n].m_p); - work_room[n].m_distance_from_contour_start - = contour_length + work_room[n].m_distance_from_edge_start; - - if (o == 0 && e == 0 && n == 0) + if (n != 0) { - m_box_min = pt; - m_box_max = pt; + vec2 delta; + delta = work_room[n].m_p - work_room[n - 1].m_p; + work_room[n].m_distance_from_edge_start = delta.magnitude() + + work_room[n - 1].m_distance_from_edge_start; } else { - m_box_min.x() = t_min(m_box_min.x(), pt.x()); - m_box_min.y() = t_min(m_box_min.y(), pt.y()); - m_box_max.x() = t_max(m_box_max.x(), pt.x()); - m_box_max.y() = t_max(m_box_max.y(), pt.y()); + work_room[n].m_distance_from_edge_start = 0.0f; } + + work_room[n].m_distance_from_contour_start + = contour_length + work_room[n].m_distance_from_edge_start; } std::list >::iterator t; @@ -155,10 +153,6 @@ TessellatedPathPrivate(const fastuidraw::Path &input, } FASTUIDRAWassert(total_needed == m_point_data.size()); } - else - { - m_box_min = m_box_max = fastuidraw::vec2(0.0f, 0.0f); - } } ////////////////////////////////////// @@ -340,7 +334,7 @@ bounding_box_min(void) const TessellatedPathPrivate *d; d = static_cast(m_d); - return d->m_box_min; + return d->m_bounding_box.min_point(); } fastuidraw::vec2 @@ -350,7 +344,7 @@ bounding_box_max(void) const TessellatedPathPrivate *d; d = static_cast(m_d); - return d->m_box_max; + return d->m_bounding_box.max_point(); } fastuidraw::vec2 @@ -360,5 +354,5 @@ bounding_box_size(void) const TessellatedPathPrivate *d; d = static_cast(m_d); - return d->m_box_max - d->m_box_min; + return d->m_bounding_box.size(); } From a9b51a2e67806e0f2c056105553029cee58247ea Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 16:38:39 +0300 Subject: [PATCH 36/52] fastuidraw/path: define arc-tessellation of a Path Change-Id: Iae9285565e16270f368fb8cf1c6f5a6ed6c96e89 --- inc/fastuidraw/arc_tessellated_path.hpp | 340 ++++++++++++++++++++++++ inc/fastuidraw/path.hpp | 37 +++ src/fastuidraw/path.cpp | 43 +++ 3 files changed, 420 insertions(+) create mode 100644 inc/fastuidraw/arc_tessellated_path.hpp diff --git a/inc/fastuidraw/arc_tessellated_path.hpp b/inc/fastuidraw/arc_tessellated_path.hpp new file mode 100644 index 000000000..485d1d8d2 --- /dev/null +++ b/inc/fastuidraw/arc_tessellated_path.hpp @@ -0,0 +1,340 @@ +/*! + * \file arc_tessellated_path.hpp + * \brief file arc_tessellated_path.hpp + * + * Copyright 2018 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + + +#pragma once + + +#include +#include +#include +#include +#include + +namespace fastuidraw { + +///@cond +class Path; +class ArcStrokedPath; +///@endcond + +/*!\addtogroup Paths + * @{ + */ + +/*! + * \brief + * An ArcTessellatedPath represents the tessellation of a Path + * into line segments and arcs. + * + * A single contour of a ArcTessellatedPath is constructed from + * a single \ref PathContour of the source \ref Path. Each + * edge of a contour of a ArcTessellatedPath is contructed from + * a single \ref PathContour::interpolator_base of the source \ref + * PathContour. The ordering of the contours of a + * ArcTessellatedPath is the same ordering as the source + * \ref PathContour objects of the source \ref Path. Also, + * the ordering of edges within a contour is the same ordering + * as the \ref PathContour::interpolator_base objects of + * the source \ref PathContour. In particular, for each contour + * of a ArcTessellatedPath, the closing edge is the last edge. + */ +class ArcTessellatedPath: + public reference_counted::non_concurrent +{ +public: + /*! + */ + enum segment_type_t + { + arc_segment, + line_segment, + }; + + /*! + * \brief + * A TessellationParams stores how finely to tessellate + * the curves of a path. + */ + class TessellationParams + { + public: + /*! + * Ctor, initializes values. + */ + TessellationParams(void): + m_threshhold(1.0f), + m_max_segments(32) + {} + + /*! + * Non-equal comparison operator. + * \param rhs value to which to compare against + */ + bool + operator!=(const TessellationParams &rhs) const + { + return m_threshhold != rhs.m_threshhold + || m_max_segments != rhs.m_max_segments; + } + + /*! + * Provided as a conveniance. Equivalent to + * \code + * m_threshhold_type = tp; + * \endcode + * \param p value to which to assign to \ref m_threshhold + */ + TessellationParams& + threshhold(float p) + { + m_threshhold = p; + return *this; + } + + /*! + * Set the value of \ref m_max_segments. + * \param v value to which to assign to \ref m_max_segments + */ + TessellationParams& + max_segments(unsigned int v) + { + m_max_segments = v; + return *this; + } + + /*! + * Meaning depends on \ref m_threshhold_type. + * Default value is 1.0. + */ + float m_threshhold; + + /*! + * Maximum number of segments to tessellate each + * PathContour::interpolator_base from each + * PathContour of a Path. Default value is 32. + */ + unsigned int m_max_segments; + }; + + /*! + * \brief + * Represents segment of an arc-tessellated path. + */ + class segment + { + public: + /*! + */ + enum segment_type_t m_type; + + /*! + * If \ref m_type is \ref line_segment, then gives the + * start position of the segment. If \ref m_type is \ref + * arc_segment, gives the center of the arc. + */ + vec2 m_p; + + /*! + * If \ref m_type is \ref line_segment, then gives the + * the position where the segment ends. If \ref m_type + * is \ref arc_segment, gives the start and end angles + * of the arc. + */ + vec2 m_data; + + /*! + * Only valid if \ref m_type is \ref arc_segment; gives + * the radius of the arc. + */ + float m_radius; + + /*! + * Gives the distance of the point from the start + * of the -contour- to the start of the segment. + */ + float m_distance_from_contour_start; + + /*! + * Gives the length of the contour open on which + * the segment lies. This value is the same for all + * segments along a fixed contour. + */ + float m_open_contour_length; + + /*! + * Gives the length of the contour closed on which + * the segment lies. This value is the same for all + * segments along a fixed contour. + */ + float m_closed_contour_length; + }; + + /*! + * Ctor. Construct a TessellatedPath from a Path + * \param input source path to tessellate + * \param P parameters on how to tessellate the source Path + */ + ArcTessellatedPath(const Path &input, TessellationParams P); + + ~ArcTessellatedPath(); + + /*! + * Returns the tessellation parameters used to construct + * this TessellatedPath. + */ + const TessellationParams& + tessellation_parameters(void) const; + + /*! + * Returns the tessellation threshold achieved + */ + float + effective_threshhold(void) const; + + /*! + * Returns the maximum number of segments any edge needed + */ + unsigned int + max_segments(void) const; + + /*! + * Returns all the segment data + */ + c_array + segment_data(void) const; + + /*! + * Returns the number of contours + */ + unsigned int + number_contours(void) const; + + /*! + * Returns the range into segment_data() for the named + * contour. + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + */ + range_type + contour_range(unsigned int contour) const; + + /*! + * Returns the range into segment_data() for the named + * contour lacking the closing edge. + * replicated (because the derivatives are different). + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + */ + range_type + unclosed_contour_range(unsigned int contour) const; + + /*! + * Returns the segment data of the named contour including + * the closing edge. Provided as a conveniance equivalent to + * \code + * point_data().sub_array(contour_range(contour)) + * \endcode + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + */ + c_array + contour_segment_data(unsigned int contour) const; + + /*! + * Returns the segment data of the named contour + * lacking the segment data of the closing edge. + * Provided as a conveniance, equivalent to + * \code + * point_data().sub_array(unclosed_contour_range(contour)) + * \endcode + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + */ + c_array + unclosed_segment_point_data(unsigned int contour) const; + + /*! + * Returns the number of edges for the named contour + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + */ + unsigned int + number_edges(unsigned int contour) const; + + /*! + * Returns the range into segment_data(void) + * for the named edge of the named contour. + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + * \param edge which edge of the contour to query, must + * have that 0 <= edge < number_edges(contour) + */ + range_type + edge_range(unsigned int contour, unsigned int edge) const; + + /*! + * Returns the segment data of the named edge of the + * named contour, provided as a conveniance, equivalent + * to + * \code + * point_data().sub_array(edge_range(contour, edge)) + * \endcode + * \param contour which path contour to query, must have + * that 0 <= contour < number_contours() + * \param edge which edge of the contour to query, must + * have that 0 <= edge < number_edges(contour) + */ + c_array + edge_point_data(unsigned int contour, unsigned int edge) const; + + /*! + * Returns the minimum point of the bounding box of + * the tessellation. + */ + vec2 + bounding_box_min(void) const; + + /*! + * Returns the maximum point of the bounding box of + * the tessellation. + */ + vec2 + bounding_box_max(void) const; + + /*! + * Returns the dimensions of the bounding box + * of the tessellated path. + */ + vec2 + bounding_box_size(void) const; + + /*! + * Returns this ArcTessellatedPath stroked. The ArcStrokedPath object + * is constructed lazily. + */ + const reference_counted_ptr& + stroked(void) const; + +private: + void *m_d; +}; + +/*! @} */ + +} diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index e71708b6c..13bd2c868 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace fastuidraw { @@ -118,6 +119,27 @@ class PathContour: c_array out_data, float *out_threshhold) const = 0; + /*! + * To be implemented by a derived class to produce the arc-tessellation + * from start_pt() to end_pt(). Only the fields ArcTessellatedPath::segment::m_p, + * and ArcTessellatedPath::m_type, ArcTessellatedPath::m_data and + * ArcTessellatedPath::m_data are to be filled; the other fields of + * ArcTessellatedPath::segment are filled by ArcTessellatedPath. + * In addition to filling the output array, the function shall return the + * number of segments needed to perform the required tessellation. + * + * \param tess_params tessellation parameters + * \param out_data location to which to write the tessellation + * \param out_threshhold location to which to write an upperbound for the + * distance between the curve and the tesseallation + * approximation. + */ + virtual + unsigned int + produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const = 0; + /*! * To be implemented by a derived class to return a fast (and approximate) * bounding box for the interpolator. @@ -171,6 +193,11 @@ class PathContour: c_array out_data, float *out_threshholds) const; virtual + unsigned int + produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const; + virtual void approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const; @@ -216,6 +243,11 @@ class PathContour: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, float *out_threshholds) const; + virtual + unsigned int + produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const; /*! * To be implemented by a derived to assist in recursive tessellation. @@ -350,6 +382,11 @@ class PathContour: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, c_array out_data, float *out_threshholds) const; + virtual + unsigned int + produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const; private: arc(const arc &q, const reference_counted_ptr &prev); diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 33f29f3ce..ec67f4e90 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -485,6 +485,15 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, return tesser.dump(out_data, out_threshhold); } +unsigned int +fastuidraw::PathContour::interpolator_generic:: +produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const +{ + /* TODO */ + return 0; +} //////////////////////////////////// // fastuidraw::PathContour::bezier methods @@ -669,6 +678,21 @@ produce_tessellation(const TessellatedPath::TessellationParams&, return 2; } +unsigned int +fastuidraw::PathContour::flat:: +produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const +{ + out_data[0].m_type = ArcTessellatedPath::line_segment; + out_data[0].m_p = start_pt(); + out_data[0].m_data = end_pt(); + out_data[0].m_radius = 0.0f; + + *out_threshhold = 0.0f; + return 1; +} + fastuidraw::PathContour::interpolator_base* fastuidraw::PathContour::flat:: deep_copy(const reference_counted_ptr &prev) const @@ -820,6 +844,25 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, return return_value; } +unsigned int +fastuidraw::PathContour::arc:: +produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, + c_array out_data, + float *out_threshhold) const +{ + ArcPrivate *d; + d = static_cast(m_d); + + out_data[0].m_type = ArcTessellatedPath::arc_segment; + out_data[0].m_p = d->m_center; + out_data[0].m_data.x() = d->m_start_angle; + out_data[0].m_data.y() = d->m_start_angle + d->m_angle_speed; + out_data[0].m_radius = d->m_radius; + + *out_threshhold = 0.0f; + return 1; +} + void fastuidraw::PathContour::arc:: approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const From 9cc2c772f5700076a0a3edf4ef8d68f491ac4a8f Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 17:33:34 +0300 Subject: [PATCH 37/52] fastuidraw/path: implement arc-tessellation Change-Id: Ia699a6abfc7f8606b6a3f91887e2e7a9d9df9ec8 --- src/fastuidraw/path.cpp | 163 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 15 deletions(-) diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index ec67f4e90..d1f9754d3 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -58,10 +58,6 @@ namespace { } - virtual - ~Tessellator() - {} - unsigned int dump(fastuidraw::c_array out_data, float *out_threshhold); @@ -76,13 +72,6 @@ namespace fill_data(fastuidraw::c_array out_data, float *out_threshhold); - bool - tessellation_satsified(unsigned int recurse_level, const float threshhold) - { - FASTUIDRAWunused(recurse_level); - return (threshhold < m_thresh.m_threshhold); - } - void add_point(const fastuidraw::vec2 &pt) { @@ -97,6 +86,40 @@ namespace std::vector m_data; }; + class ArcTessellator + { + public: + ArcTessellator(const fastuidraw::ArcTessellatedPath::TessellationParams &tess_params, + const fastuidraw::PathContour::interpolator_generic *h): + m_h(h), + m_thresh_sq(tess_params.m_threshhold * tess_params.m_threshhold), + m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), + m_max_size(tess_params.m_max_segments + 1) + { + } + + unsigned int + dump(fastuidraw::c_array out_data, + float *out_threshhold); + + private: + void + tessellation_worker(unsigned int recurse_level, + fastuidraw::PathContour::interpolator_generic::tessellated_region *in_L, + fastuidraw::PathContour::interpolator_generic::tessellated_region *in_R, + fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, + float *out_threshhold_sq); + + unsigned int + fill_data(fastuidraw::c_array out_data, + float *out_threshhold); + + const fastuidraw::PathContour::interpolator_generic *m_h; + float m_thresh_sq; + unsigned int m_max_recursion, m_max_size; + std::vector m_data; + }; + class InterpolatorBasePrivate { public: @@ -361,7 +384,7 @@ tessellation_worker(unsigned int recurse_level, m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshhold); if (recurse_level + 1u < m_max_recursion - && !tessellation_satsified(recurse_level, *out_threshhold)) + && *out_threshhold > m_thresh.m_threshhold) { float tmpA(-1.0f), tmpB(-1.0f); @@ -397,6 +420,110 @@ tessellation_worker(unsigned int recurse_level, } } +/////////////////////////////////////// +// ArcTessellator methods +unsigned int +ArcTessellator:: +dump(fastuidraw::c_array out_data, + float *out_threshhold) +{ + using namespace fastuidraw; + + PathContour::interpolator_generic::tessellated_region *L, *R; + vec2 mid; + float thresh_sq(0.0f); + + m_h->tessellate(nullptr, &L, &R, &mid, nullptr); + tessellation_worker(1, L, R, m_h->start_pt(), mid, m_h->end_pt(), &thresh_sq); + *out_threshhold = t_sqrt(thresh_sq); + + FASTUIDRAWassert(m_data.size() <= out_data.size()); + std::copy(m_data.begin(), m_data.end(), out_data.begin()); + return m_data.size(); +} + +void +ArcTessellator:: +tessellation_worker(unsigned int recurse_level, + fastuidraw::PathContour::interpolator_generic::tessellated_region *inL, + fastuidraw::PathContour::interpolator_generic::tessellated_region *inR, + fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, + float *out_threshhold_sq) +{ + using namespace fastuidraw; + PathContour::interpolator_generic::tessellated_region *L0(nullptr), *L1(nullptr); + PathContour::interpolator_generic::tessellated_region *R0(nullptr), *R1(nullptr); + vec2 midL, midR; + static float tol(0.00001f); + + m_h->tessellate(inL, &L0, &L1, &midL, nullptr); + m_h->tessellate(inR, &R0, &R1, &midR, nullptr); + + /* compute the circle going through start, mid, end */ + vec2 c, v0, v1, n0, n1, p0, p1; + float s, det; + + p0 = 0.5f * (start + mid); + p1 = 0.5f * (mid + end); + + v0 = start - mid; + n0 = vec2(-v0.y(), v0.x()); + + v1 = mid - start; + n1 = vec2(-v1.y(), v1.x()); + + det = n1.y() * n0.x() - n0.y() * n1.x(); + if (t_abs(det) < tol) + { + /* practically flat anyways, just add a line segment */ + ArcTessellatedPath::segment S; + + S.m_type = ArcTessellatedPath::line_segment; + S.m_p = start; + S.m_data = end; + S.m_radius = 0.0f; + m_data.push_back(S); + + /* TODO: compute the distance of mid, midL and midR from + * the segment and use that as the output threshhold + */ + *out_threshhold_sq = 0.0f; + return; + } + + s = dot(v1, p1 - p0) / det; + c = p0 + s * n0; + + /* we are done if both midL and midR are close enough to C */ + float threshLsq, threshRsq; + + threshLsq = (c - midL).magnitudeSq(); + threshRsq = (c - midR).magnitudeSq(); + *out_threshhold_sq = t_max(threshLsq, threshRsq); + + if (recurse_level + 1u < m_max_recursion + && *out_threshhold_sq > m_thresh_sq) + { + tessellation_worker(recurse_level + 1u, L0, L1, + start, midL, mid, &threshLsq); + tessellation_worker(recurse_level + 1u, R0, R1, + mid, midR, end, &threshRsq); + *out_threshhold_sq = t_max(threshLsq, threshRsq); + } + else + { + ArcTessellatedPath::segment S; + + S.m_type = ArcTessellatedPath::arc_segment; + S.m_p = c; + S.m_radius = (mid - c).magnitude(); + + S.m_data.x() = std::atan2(start.y() - c.y(), start.x() - c.x()); + S.m_data.y() = std::atan2(end.y() - c.y(), end.x() - c.x()); + m_data.push_back(S); + } +} + //////////////////////////////////////// // BezierPrivate methods void @@ -491,8 +618,8 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, c_array out_data, float *out_threshhold) const { - /* TODO */ - return 0; + ArcTessellator tesser(tess_params, this); + return tesser.dump(out_data, out_threshhold); } //////////////////////////////////// @@ -639,7 +766,11 @@ tessellate(tessellated_region *in_region, *out_regionA = newA; *out_regionB = newB; *out_p = newA->m_pts.back(); - *out_threshhold = t_max(newA->compute_curve_distance(), newB->compute_curve_distance()); + + if (out_threshhold) + { + *out_threshhold = t_max(newA->compute_curve_distance(), newB->compute_curve_distance()); + } } fastuidraw::PathContour::interpolator_base* @@ -684,6 +815,7 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, c_array out_data, float *out_threshhold) const { + FASTUIDRAWunused(tess_params); out_data[0].m_type = ArcTessellatedPath::line_segment; out_data[0].m_p = start_pt(); out_data[0].m_data = end_pt(); @@ -853,6 +985,7 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcPrivate *d; d = static_cast(m_d); + FASTUIDRAWunused(tess_params); out_data[0].m_type = ArcTessellatedPath::arc_segment; out_data[0].m_p = d->m_center; out_data[0].m_data.x() = d->m_start_angle; From 85f411996b5f7276dd91ce027368b36eefb61cd0 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 11:00:45 +0300 Subject: [PATCH 38/52] fastuidraw: implement arc_tessellated_path Change-Id: I04953bb92970b6e42aa76710b255340d940fda42 --- inc/fastuidraw/arc_tessellated_path.hpp | 35 ++- src/fastuidraw/Rules.mk | 5 +- src/fastuidraw/arc_tessellated_path.cpp | 368 ++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 8 deletions(-) create mode 100644 src/fastuidraw/arc_tessellated_path.cpp diff --git a/inc/fastuidraw/arc_tessellated_path.hpp b/inc/fastuidraw/arc_tessellated_path.hpp index 485d1d8d2..cb04df0a3 100644 --- a/inc/fastuidraw/arc_tessellated_path.hpp +++ b/inc/fastuidraw/arc_tessellated_path.hpp @@ -140,6 +140,8 @@ class ArcTessellatedPath: { public: /*! + * Specifies the segment type which in turn determines the + * meaning of \ref m_p, \ref m_data and \ref m_radius */ enum segment_type_t m_type; @@ -165,11 +167,30 @@ class ArcTessellatedPath: float m_radius; /*! - * Gives the distance of the point from the start - * of the -contour- to the start of the segment. + * Gives the length of the segment. + */ + float m_length; + + /*! + * Gives the distance of the start of the segment from + * the start of the edge (i.e PathContour::interpolator_base). + */ + float m_distance_from_edge_start; + + /*! + * Gives the distance of the start of segment to the + * start of the -contour-. */ float m_distance_from_contour_start; + /*! + * Gives the length of the edge (i.e. + * PathContour::interpolator_base) on which the + * segment lies. This value is the same for all + * segments along a fixed edge. + */ + float m_edge_length; + /*! * Gives the length of the contour open on which * the segment lies. This value is the same for all @@ -248,7 +269,7 @@ class ArcTessellatedPath: * Returns the segment data of the named contour including * the closing edge. Provided as a conveniance equivalent to * \code - * point_data().sub_array(contour_range(contour)) + * segment_data().sub_array(contour_range(contour)) * \endcode * \param contour which path contour to query, must have * that 0 <= contour < number_contours() @@ -261,13 +282,13 @@ class ArcTessellatedPath: * lacking the segment data of the closing edge. * Provided as a conveniance, equivalent to * \code - * point_data().sub_array(unclosed_contour_range(contour)) + * segment_data().sub_array(unclosed_contour_range(contour)) * \endcode * \param contour which path contour to query, must have * that 0 <= contour < number_contours() */ c_array - unclosed_segment_point_data(unsigned int contour) const; + unclosed_contour_segment_data(unsigned int contour) const; /*! * Returns the number of edges for the named contour @@ -293,7 +314,7 @@ class ArcTessellatedPath: * named contour, provided as a conveniance, equivalent * to * \code - * point_data().sub_array(edge_range(contour, edge)) + * segment_data().sub_array(edge_range(contour, edge)) * \endcode * \param contour which path contour to query, must have * that 0 <= contour < number_contours() @@ -301,7 +322,7 @@ class ArcTessellatedPath: * have that 0 <= edge < number_edges(contour) */ c_array - edge_point_data(unsigned int contour, unsigned int edge) const; + edge_segment_data(unsigned int contour, unsigned int edge) const; /*! * Returns the minimum point of the bounding box of diff --git a/src/fastuidraw/Rules.mk b/src/fastuidraw/Rules.mk index f56f754b7..84e279990 100644 --- a/src/fastuidraw/Rules.mk +++ b/src/fastuidraw/Rules.mk @@ -28,7 +28,10 @@ include $(dir)/Rules.mk dir := $(d)/gl_backend include $(dir)/Rules.mk -FASTUIDRAW_SOURCES += $(call filelist, image.cpp colorstop.cpp colorstop_atlas.cpp path.cpp tessellated_path.cpp) +FASTUIDRAW_SOURCES += $(call filelist, image.cpp colorstop.cpp \ + colorstop_atlas.cpp path.cpp tessellated_path.cpp \ + arc_tessellated_path.cpp) + NEGL_SRCS += $(call filelist, egl_binding.cpp) # Begin standard footer diff --git a/src/fastuidraw/arc_tessellated_path.cpp b/src/fastuidraw/arc_tessellated_path.cpp new file mode 100644 index 000000000..1bbe513f1 --- /dev/null +++ b/src/fastuidraw/arc_tessellated_path.cpp @@ -0,0 +1,368 @@ +/*! + * \file arc_tessellated_path.cpp + * \brief file arc_tessellated_path.cpp + * + * Copyright 2018 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + + +#include +#include +#include +#include +#include +#include +#include "private/util_private.hpp" +#include "private/bounding_box.hpp" + +namespace +{ + class ArcTessellatedPathPrivate + { + public: + ArcTessellatedPathPrivate(const fastuidraw::Path &input, + fastuidraw::ArcTessellatedPath::TessellationParams TP); + + std::vector > > m_edge_ranges; + std::vector m_segment_data; + fastuidraw::BoundingBox m_bounding_box; + fastuidraw::ArcTessellatedPath::TessellationParams m_params; + float m_effective_threshhold; + unsigned int m_max_segments; + }; + + void + union_segment(const fastuidraw::ArcTessellatedPath::segment &S, + fastuidraw::BoundingBox &BB) + { + using namespace fastuidraw; + if (S.m_type == ArcTessellatedPath::line_segment) + { + BB.union_point(S.m_p); + BB.union_point(S.m_data); + } + else + { + vec2 s, e; + for (int i = 0; i < 2; ++i) + { + vec2 q; + q = S.m_p + S.m_radius * vec2(t_cos(S.m_data[i]), t_sin(S.m_data[i])); + BB.union_point(q); + } + } + } + + float + segment_length(const fastuidraw::ArcTessellatedPath::segment &S) + { + using namespace fastuidraw; + if (S.m_type == ArcTessellatedPath::line_segment) + { + return (S.m_p - S.m_data).magnitude(); + } + else + { + return t_abs(S.m_data[0] - S.m_data[1]) * S.m_radius; + } + } +} + +////////////////////////////////////////////// +// TessellatedPathPrivate methods +ArcTessellatedPathPrivate:: +ArcTessellatedPathPrivate(const fastuidraw::Path &input, + fastuidraw::ArcTessellatedPath::TessellationParams TP): + m_edge_ranges(input.number_contours()), + m_params(TP), + m_effective_threshhold(0.0f), + m_max_segments(0u) +{ + using namespace fastuidraw; + + if (input.number_contours() > 0) + { + std::list > temp; + std::vector work_room; + std::list >::const_iterator iter, end_iter; + + for(unsigned int loc = 0, o = 0, endo = input.number_contours(); o < endo; ++o) + { + reference_counted_ptr contour(input.contour(o)); + float contour_length(0.0f), open_contour_length(0.0f), closed_contour_length(0.0f); + std::list >::iterator start_contour; + + m_edge_ranges[o].resize(contour->number_points()); + for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) + { + unsigned int needed; + float tmp; + + work_room.resize(m_params.m_max_segments + 1); + temp.push_back(std::vector()); + needed = contour->interpolator(e)->produce_tessellation(m_params, + make_c_array(work_room), + &tmp); + m_edge_ranges[o][e] = range_type(loc, loc + needed); + loc += needed; + + FASTUIDRAWassert(needed > 0u); + m_max_segments = t_max(m_max_segments, needed - 1); + m_effective_threshhold = t_max(m_effective_threshhold, tmp); + + work_room.resize(needed); + for(unsigned int n = 0; n < work_room.size(); ++n) + { + union_segment(work_room[n], m_bounding_box); + work_room[n].m_length = segment_length(work_room[n]); + + if (n != 0) + { + work_room[n].m_distance_from_edge_start = + work_room[n - 1].m_distance_from_edge_start + + work_room[n - 1].m_length; + } + else + { + work_room[n].m_distance_from_edge_start = 0.0f; + } + + work_room[n].m_distance_from_contour_start + = contour_length + work_room[n].m_distance_from_edge_start; + } + + std::list >::iterator t; + t = temp.insert(temp.end(), work_room); + if (e == 0) + { + start_contour = t; + } + + contour_length = temp.back().back().m_distance_from_contour_start + + temp.back().back().m_length; + + if (e + 2 == ende) + { + open_contour_length = contour_length; + } + else if (e + 1 == ende) + { + closed_contour_length = contour_length; + } + + for(unsigned int n = 0; n < needed; ++n) + { + (*t)[n].m_edge_length = (*t)[needed - 1].m_distance_from_edge_start + + (*t)[needed - 1].m_length; + } + } + + for(std::list >::iterator + t = start_contour, endt = temp.end(); t != endt; ++t) + { + for(unsigned int e = 0, ende = t->size(); e < ende; ++e) + { + (*t)[e].m_open_contour_length = open_contour_length; + (*t)[e].m_closed_contour_length = closed_contour_length; + } + } + } + + unsigned int total_needed; + + total_needed = m_edge_ranges.back().back().m_end; + m_segment_data.reserve(total_needed); + for(iter = temp.begin(), end_iter = temp.end(); iter != end_iter; ++iter) + { + std::copy(iter->begin(), iter->end(), std::back_inserter(m_segment_data)); + } + FASTUIDRAWassert(total_needed == m_segment_data.size()); + } +} + +////////////////////////////////////// +// fastuidraw::ArcTessellatedPath methods +fastuidraw::ArcTessellatedPath:: +ArcTessellatedPath(const Path &input, + fastuidraw::ArcTessellatedPath::TessellationParams TP) +{ + ArcTessellatedPathPrivate *d; + m_d = d = FASTUIDRAWnew ArcTessellatedPathPrivate(input, TP); +} + +fastuidraw::ArcTessellatedPath:: +~ArcTessellatedPath() +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + FASTUIDRAWdelete(d); + m_d = nullptr; +} + +const fastuidraw::ArcTessellatedPath::TessellationParams& +fastuidraw::ArcTessellatedPath:: +tessellation_parameters(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_params; +} + +float +fastuidraw::ArcTessellatedPath:: +effective_threshhold(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + return d->m_effective_threshhold; +} + +unsigned int +fastuidraw::ArcTessellatedPath:: +max_segments(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + return d->m_max_segments; +} + +fastuidraw::c_array +fastuidraw::ArcTessellatedPath:: +segment_data(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return make_c_array(d->m_segment_data); +} + +unsigned int +fastuidraw::ArcTessellatedPath:: +number_contours(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_edge_ranges.size(); +} + +fastuidraw::range_type +fastuidraw::ArcTessellatedPath:: +contour_range(unsigned int contour) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return range_type(d->m_edge_ranges[contour].front().m_begin, + d->m_edge_ranges[contour].back().m_end); +} + +fastuidraw::range_type +fastuidraw::ArcTessellatedPath:: +unclosed_contour_range(unsigned int contour) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + range_type return_value; + unsigned int num_edges(number_edges(contour)); + + return_value.m_begin = d->m_edge_ranges[contour].front().m_begin; + return_value.m_end = (num_edges > 1) ? + d->m_edge_ranges[contour][num_edges - 2].m_end: + d->m_edge_ranges[contour][num_edges - 1].m_end; + + return return_value; +} + +fastuidraw::c_array +fastuidraw::ArcTessellatedPath:: +contour_segment_data(unsigned int contour) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return make_c_array(d->m_segment_data).sub_array(contour_range(contour)); +} + +fastuidraw::c_array +fastuidraw::ArcTessellatedPath:: +unclosed_contour_segment_data(unsigned int contour) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return make_c_array(d->m_segment_data).sub_array(unclosed_contour_range(contour)); +} + +unsigned int +fastuidraw::ArcTessellatedPath:: +number_edges(unsigned int contour) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_edge_ranges[contour].size(); +} + +fastuidraw::range_type +fastuidraw::ArcTessellatedPath:: +edge_range(unsigned int contour, unsigned int edge) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_edge_ranges[contour][edge]; +} + +fastuidraw::c_array +fastuidraw::ArcTessellatedPath:: +edge_segment_data(unsigned int contour, unsigned int edge) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return make_c_array(d->m_segment_data).sub_array(edge_range(contour, edge)); +} + +fastuidraw::vec2 +fastuidraw::ArcTessellatedPath:: +bounding_box_min(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_bounding_box.min_point(); +} + +fastuidraw::vec2 +fastuidraw::ArcTessellatedPath:: +bounding_box_max(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_bounding_box.max_point();; +} + +fastuidraw::vec2 +fastuidraw::ArcTessellatedPath:: +bounding_box_size(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + + return d->m_bounding_box.size(); +} From 5b47612931fd9682ab16be16e4b9adda316f7c52 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Mon, 30 Apr 2018 17:39:30 +0300 Subject: [PATCH 39/52] fastuidraw/painter: define ArcStrokedPath Change-Id: I7688ef2e98934fdd435b00bbe6bc0d92f64c07ba --- inc/fastuidraw/painter/arc_stroked_path.hpp | 199 ++++++++++++++++++++ inc/fastuidraw/painter/stroked_point.hpp | 43 +++++ 2 files changed, 242 insertions(+) create mode 100644 inc/fastuidraw/painter/arc_stroked_path.hpp diff --git a/inc/fastuidraw/painter/arc_stroked_path.hpp b/inc/fastuidraw/painter/arc_stroked_path.hpp new file mode 100644 index 000000000..ae62e724e --- /dev/null +++ b/inc/fastuidraw/painter/arc_stroked_path.hpp @@ -0,0 +1,199 @@ +/*! + * \file stroked_path.hpp + * \brief file stroked_path.hpp + * + * Copyright 2016 by Intel. + * + * Contact: kevin.rogovin@intel.com + * + * This Source Code Form is subject to the + * terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with + * this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * \author Kevin Rogovin + * + */ + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fastuidraw { + +///@cond +class ArcTessellatedPath; +class Path; +class PainterAttribute; +class PainterAttributeData; +///@endcond + +/*!\addtogroup Paths + * @{ + */ + +/*! + * \brief + * A ArcStrokedPath represents the data needed to draw a path stroked. + * In contrast to StrokedPath, an ArcStrokedPath will use arc-edges + * to approximate the edges of a Path, resulting in far few vertices. + * It contains -all- the data needed to stroke a path regardless of + * stroking style. In particular, for a given TessellatedPath, + * one only needs to construct a ArcStrokedPath once regardless + * of how one strokes the original path for drawing. + * + * The data is stored as \ref PainterAttributeData, a seperate + * object for edges, each type of join and each type of caps. + * What chunks to use from these objects is computed by + * the member function compute_chunks(); the PainterAttributeData + * chunking for joins and caps is the same regardless of + * the cap and join type. + */ +class ArcStrokedPath: + public reference_counted::non_concurrent +{ +public: + /*! + * \brief + * Opaque object to hold work room needed for functions + * of ArcStrokedPath that require scratch space. + */ + class ScratchSpace:fastuidraw::noncopyable + { + public: + ScratchSpace(void); + ~ScratchSpace(); + private: + friend class ArcStrokedPath; + void *m_d; + }; + + /*! + * \brief + * Object to hold the output of a chunk query via compute_chunks(). + */ + class ChunkSet:fastuidraw::noncopyable + { + public: + ChunkSet(void); + + ~ChunkSet(); + + /*! + * The list of chunks to take from ArcStrokedPath::edges() + * that have visible content. + */ + c_array + edge_chunks(void) const; + + private: + friend class ArcStrokedPath; + void *m_d; + }; + + /*! + * Enumeration to select the chunk of all edges of the closing + * edges or all edges of the non-closing edges of a ArcStrokedPath. + */ + enum chunk_selection + { + /*! + * Select the chunk that holds all the edges of + * ONLY the non-closing edges of the ArcStrokedPath + */ + all_non_closing = StrokedCapsJoins::all_non_closing, + + /*! + * Select the chunk that holds all the edges of + * ONLY the closing edges of the ArcStrokedPath + */ + all_closing = StrokedCapsJoins::all_closing, + }; + + /*! + * Ctor. Construct a ArcStrokedPath from the data + * of a TessellatedPath. + * \param P source ArcTessellatedPath + */ + explicit + ArcStrokedPath(const ArcTessellatedPath &P); + + ~ArcStrokedPath(); + + /*! + * Given a set of clip equations in clip coordinates + * and a tranformation from local coordiante to clip + * coordinates, compute what chunks are not completely + * culled by the clip equations. + * \param scratch_space scratch space for computations + * \param clip_equations array of clip equations + * \param clip_matrix_local 3x3 transformation from local (x, y, 1) + * coordinates to clip coordinates. + * \param recip_dimensions holds the reciprocal of the dimensions of the viewport + * \param pixels_additional_room amount in -pixels- to push clip equations by + * to grab additional edges + * \param item_space_additional_room amount in local coordinates to push clip + * equations by to grab additional edges + * draw the closing edges of each contour + * \param include_closing_edges if true include the chunks needed to + * \param max_attribute_cnt only allow those chunks for which have no more + * than max_attribute_cnt attributes + * \param max_index_cnt only allow those chunks for which have no more + * than max_index_cnt indices + * \param take_joins_outside_of_region if true, take even those joins outside of the region + * (this is for handling miter-joins where the weather + * or not a miter-join is included is also a function of + * the miter-limit when stroking). + * \param[out] dst location to which to write output + */ + void + compute_chunks(ScratchSpace &scratch_space, + c_array clip_equations, + const float3x3 &clip_matrix_local, + const vec2 &recip_dimensions, + float pixels_additional_room, + float item_space_additional_room, + bool include_closing_edges, + unsigned int max_attribute_cnt, + unsigned int max_index_cnt, + ChunkSet &dst) const; + + /*! + * Returns the data to draw the edges of a stroked path. + */ + const PainterAttributeData& + edges(void) const; + + /*! + * Return the chunk to feed to edges() that holds all + * the edges of the closing edges or all the edges + * of the non-closing edges. + * \param c select edges of closing or non-closing edges + */ + unsigned int + chunk_of_edges(enum chunk_selection c) const; + + /*! + * Returns the StrokedCapsJoins of the ArcStrokedPath that + * provides the attribute data for the stroking of the + * joins and caps. + */ + const StrokedCapsJoins& + caps_joins(void) const; + +private: + void *m_d; +}; + +/*! @} */ + +} diff --git a/inc/fastuidraw/painter/stroked_point.hpp b/inc/fastuidraw/painter/stroked_point.hpp index 362d93965..29e5768f1 100644 --- a/inc/fastuidraw/painter/stroked_point.hpp +++ b/inc/fastuidraw/painter/stroked_point.hpp @@ -78,6 +78,18 @@ class StrokedPoint */ offset_shared_with_edge, + /*! + * The point is a point to bound an arc-edge which is to be used for + * stroking an arc where rather than approximating the arc-edge with + * a sequence of line segments, a pixel shader is used to determine + * if inside or outside of the arc. + * - \ref m_position holds the center of the circle of the arc + * - \ref m_pre_offset radius of the circle of the arc + * - \ref m_auxilary holds the angle range of the arc, the start + * at .x() and the end at .y(). + */ + offset_edge_arc, + /*! * The point is for a boundary point of a rounded join of the path. * The meanings of the members \ref m_pre_offset and and \ref @@ -247,6 +259,27 @@ class StrokedPoint number_common_bits, }; + /*! + * \brief + * Enumeration encoding of bits of point::m_packed_data + * for those with offset type \ref offset_edge_arc + */ + enum packed_data_bit_layout_arc_edge_t + { + /*! + * If bit is up, indicates that the arc edge point + * is to be extended away from the center when stroking + * (i.e. it is the outside of teh stroking edge). + */ + outside_arc_bit = number_common_bits, + + /*! + * If bit is up, indicates that the arc edge point + * is at the end of the arc. + */ + end_of_arc_bit, + }; + /*! * \brief * Enumeration encoding of bits of point::m_packed_data @@ -339,6 +372,16 @@ class StrokedPoint */ offset_type_mask = FASTUIDRAW_MASK(offset_type_bit0, offset_type_num_bits), + /*! + * Mask generated for \ref outside_arc_bit + */ + outside_arc_mask = FASTUIDRAW_MASK(outside_arc_bit, 1), + + /*! + * Mask generated for \ref end_of_arc_bit + */ + end_of_arc_mask = FASTUIDRAW_MASK(end_of_arc_bit, 1), + /*! * Mask generated for \ref normal0_y_sign_bit */ From c52fc3a80a13b6d6263ce01f1a6ee20d88fd4766 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 13:05:36 +0300 Subject: [PATCH 40/52] demo_data/paths: add default path Change-Id: I5330587cc081bb69b62c9063c210e327e0a6977a --- demo_data/paths/default_path.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 demo_data/paths/default_path.txt diff --git a/demo_data/paths/default_path.txt b/demo_data/paths/default_path.txt new file mode 100644 index 000000000..3afcd64e8 --- /dev/null +++ b/demo_data/paths/default_path.txt @@ -0,0 +1,11 @@ +[ (50.0, 35.0) [[(60.0, 50.0)]] (70.0, 35.0) + arc 180 (70.0, -100.0) + [[(60.0, -150.0) (30.0, -50.0)]] + (0.0, -100.0) arc 90] + + +[ (200, 200) (400, 200) (400, 400) (200, 400)] + +[ (-50, 100) (0, 200) (100, 300) (150, 325) (150, 100)] + +[(300 300)] From 284e1576035ed08e4801c537fc88b757501495c8 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 13:05:50 +0300 Subject: [PATCH 41/52] fastuidraw/path: arc-tessellation fixes Change-Id: I90b21a2f673236aad4c39e798671e64e38eb0b2b --- src/fastuidraw/path.cpp | 84 ++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index d1f9754d3..92c81735d 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -24,6 +24,7 @@ #include #include "private/util_private.hpp" #include "private/path_util_private.hpp" +#include "private/util_private_ostream.hpp" #include "private/bounding_box.hpp" namespace @@ -92,7 +93,7 @@ namespace ArcTessellator(const fastuidraw::ArcTessellatedPath::TessellationParams &tess_params, const fastuidraw::PathContour::interpolator_generic *h): m_h(h), - m_thresh_sq(tess_params.m_threshhold * tess_params.m_threshhold), + m_thresh(tess_params.m_threshhold), m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), m_max_size(tess_params.m_max_segments + 1) { @@ -115,7 +116,7 @@ namespace float *out_threshhold); const fastuidraw::PathContour::interpolator_generic *m_h; - float m_thresh_sq; + float m_thresh; unsigned int m_max_recursion, m_max_size; std::vector m_data; }; @@ -431,11 +432,19 @@ dump(fastuidraw::c_array out_data, PathContour::interpolator_generic::tessellated_region *L, *R; vec2 mid; - float thresh_sq(0.0f); m_h->tessellate(nullptr, &L, &R, &mid, nullptr); - tessellation_worker(1, L, R, m_h->start_pt(), mid, m_h->end_pt(), &thresh_sq); - *out_threshhold = t_sqrt(thresh_sq); + tessellation_worker(1, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); + + if (L) + { + FASTUIDRAWdelete(L); + } + + if (R) + { + FASTUIDRAWdelete(R); + } FASTUIDRAWassert(m_data.size() <= out_data.size()); std::copy(m_data.begin(), m_data.end(), out_data.begin()); @@ -448,7 +457,7 @@ tessellation_worker(unsigned int recurse_level, fastuidraw::PathContour::interpolator_generic::tessellated_region *inL, fastuidraw::PathContour::interpolator_generic::tessellated_region *inR, fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, - float *out_threshhold_sq) + float *out_threshhold) { using namespace fastuidraw; PathContour::interpolator_generic::tessellated_region *L0(nullptr), *L1(nullptr); @@ -461,7 +470,7 @@ tessellation_worker(unsigned int recurse_level, /* compute the circle going through start, mid, end */ vec2 c, v0, v1, n0, n1, p0, p1; - float s, det; + float s, det, r; p0 = 0.5f * (start + mid); p1 = 0.5f * (mid + end); @@ -469,7 +478,7 @@ tessellation_worker(unsigned int recurse_level, v0 = start - mid; n0 = vec2(-v0.y(), v0.x()); - v1 = mid - start; + v1 = mid - end; n1 = vec2(-v1.y(), v1.x()); det = n1.y() * n0.x() - n0.y() * n1.x(); @@ -487,28 +496,50 @@ tessellation_worker(unsigned int recurse_level, /* TODO: compute the distance of mid, midL and midR from * the segment and use that as the output threshhold */ - *out_threshhold_sq = 0.0f; + *out_threshhold = 0.0f; + if (L0) + { + FASTUIDRAWdelete(L0); + } + if (L1) + { + FASTUIDRAWdelete(L1); + } + if (R0) + { + FASTUIDRAWdelete(R0); + } + if (R1) + { + FASTUIDRAWdelete(R1); + } return; } s = dot(v1, p1 - p0) / det; c = p0 + s * n0; + r = (c - mid).magnitude(); + + std::cout << "r = " << r + << ", r_start = " << (c - start).magnitude() + << ", r_end = " << (c - end).magnitude() + << "\n"; /* we are done if both midL and midR are close enough to C */ - float threshLsq, threshRsq; + float threshL, threshR; - threshLsq = (c - midL).magnitudeSq(); - threshRsq = (c - midR).magnitudeSq(); - *out_threshhold_sq = t_max(threshLsq, threshRsq); + threshL = t_abs(r - (c - midL).magnitude()); + threshR = t_abs(r - (c - midR).magnitude()); + *out_threshhold = t_max(threshL, threshR); if (recurse_level + 1u < m_max_recursion - && *out_threshhold_sq > m_thresh_sq) + && *out_threshhold > m_thresh) { tessellation_worker(recurse_level + 1u, L0, L1, - start, midL, mid, &threshLsq); + start, midL, mid, &threshL); tessellation_worker(recurse_level + 1u, R0, R1, - mid, midR, end, &threshRsq); - *out_threshhold_sq = t_max(threshLsq, threshRsq); + mid, midR, end, &threshR); + *out_threshhold = t_max(threshL, threshR); } else { @@ -516,12 +547,29 @@ tessellation_worker(unsigned int recurse_level, S.m_type = ArcTessellatedPath::arc_segment; S.m_p = c; - S.m_radius = (mid - c).magnitude(); + S.m_radius = r; S.m_data.x() = std::atan2(start.y() - c.y(), start.x() - c.x()); S.m_data.y() = std::atan2(end.y() - c.y(), end.x() - c.x()); m_data.push_back(S); } + + if (L0) + { + FASTUIDRAWdelete(L0); + } + if (L1) + { + FASTUIDRAWdelete(L1); + } + if (R0) + { + FASTUIDRAWdelete(R0); + } + if (R1) + { + FASTUIDRAWdelete(R1); + } } //////////////////////////////////////// From 60d8554723731f3b1c74cd96e6047a2faf49a75a Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 13:53:35 +0300 Subject: [PATCH 42/52] fastuidraw/path: force recuse if circle is flat; this allows for handling the bad luck of when the middle point of a (sub)curve is collinear with the end points of the (sub)curve Change-Id: I1cf6c98519c55d3514415be0bfc9b3de6386aec0 --- src/fastuidraw/path.cpp | 44 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 92c81735d..b085e1e31 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -471,6 +471,7 @@ tessellation_worker(unsigned int recurse_level, /* compute the circle going through start, mid, end */ vec2 c, v0, v1, n0, n1, p0, p1; float s, det, r; + float threshL, threshR; p0 = 0.5f * (start + mid); p1 = 0.5f * (mid + end); @@ -484,19 +485,31 @@ tessellation_worker(unsigned int recurse_level, det = n1.y() * n0.x() - n0.y() * n1.x(); if (t_abs(det) < tol) { - /* practically flat anyways, just add a line segment */ - ArcTessellatedPath::segment S; - - S.m_type = ArcTessellatedPath::line_segment; - S.m_p = start; - S.m_data = end; - S.m_radius = 0.0f; - m_data.push_back(S); + if (recurse_level + 1u < m_max_recursion) + { + tessellation_worker(recurse_level + 1u, L0, L1, + start, midL, mid, &threshL); + tessellation_worker(recurse_level + 1u, R0, R1, + mid, midR, end, &threshR); + *out_threshhold = t_max(threshL, threshR); + } + else + { + /* practically flat anyways, just add a line segment */ + ArcTessellatedPath::segment S; + + S.m_type = ArcTessellatedPath::line_segment; + S.m_p = start; + S.m_data = end; + S.m_radius = 0.0f; + m_data.push_back(S); + + /* TODO: compute the distance of mid, midL and midR from + * the segment and use that as the output threshhold + */ + *out_threshhold = 0.0f; + } - /* TODO: compute the distance of mid, midL and midR from - * the segment and use that as the output threshhold - */ - *out_threshhold = 0.0f; if (L0) { FASTUIDRAWdelete(L0); @@ -520,14 +533,7 @@ tessellation_worker(unsigned int recurse_level, c = p0 + s * n0; r = (c - mid).magnitude(); - std::cout << "r = " << r - << ", r_start = " << (c - start).magnitude() - << ", r_end = " << (c - end).magnitude() - << "\n"; - /* we are done if both midL and midR are close enough to C */ - float threshL, threshR; - threshL = t_abs(r - (c - midL).magnitude()); threshR = t_abs(r - (c - midR).magnitude()); *out_threshhold = t_max(threshL, threshR); From f6c5a1cd26674de177f72dcf4d242e17e3675b64 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 14:25:31 +0300 Subject: [PATCH 43/52] fastuidraw/path: cleanup tessellation code by using reference counted pointers Change-Id: Ic39d7780078742057b5c22b865ce1c8f38e527bd --- inc/fastuidraw/path.hpp | 20 +++--- src/fastuidraw/path.cpp | 137 ++++++++++++++-------------------------- 2 files changed, 56 insertions(+), 101 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 13bd2c868..2b6e92be8 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -219,13 +219,9 @@ class PathContour: * A tessellated_region is a base class for a cookie * used and generated by tessellate(). */ - class tessellated_region - { - public: - virtual - ~tessellated_region() - {} - }; + class tessellated_region: + public reference_counted::non_concurrent + {}; /*! * Ctor. @@ -264,8 +260,9 @@ class PathContour: */ virtual void - tessellate(tessellated_region *in_region, - tessellated_region **out_regionA, tessellated_region **out_regionB, + tessellate(reference_counted_ptr in_region, + reference_counted_ptr *out_regionA, + reference_counted_ptr *out_regionB, vec2 *out_p, float *out_threshholds) const = 0; }; @@ -314,8 +311,9 @@ class PathContour: virtual void - tessellate(tessellated_region *in_region, - tessellated_region **out_regionA, tessellated_region **out_regionB, + tessellate(reference_counted_ptr in_region, + reference_counted_ptr *out_regionA, + reference_counted_ptr *out_regionB, vec2 *out_p, float *out_threshholds) const; virtual void diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index b085e1e31..292e47bf3 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -50,8 +50,14 @@ namespace class Tessellator:fastuidraw::noncopyable { public: - Tessellator(const fastuidraw::TessellatedPath::TessellationParams &tess_params, - const fastuidraw::PathContour::interpolator_generic *h): + typedef fastuidraw::PathContour PathContour; + typedef PathContour::interpolator_generic interpolator_generic; + typedef interpolator_generic::tessellated_region tessellated_region; + typedef fastuidraw::TessellatedPath TessellatedPath; + typedef TessellatedPath::TessellationParams TessellationParams; + + Tessellator(const TessellationParams &tess_params, + const interpolator_generic *h): m_h(h), m_thresh(tess_params), m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), @@ -60,38 +66,44 @@ namespace } unsigned int - dump(fastuidraw::c_array out_data, + dump(fastuidraw::c_array out_data, float *out_threshhold); private: void tessellation_worker(unsigned int recurse_level, - fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, + fastuidraw::reference_counted_ptr in_src, float *out_threshhold); unsigned int - fill_data(fastuidraw::c_array out_data, + fill_data(fastuidraw::c_array out_data, float *out_threshhold); void add_point(const fastuidraw::vec2 &pt) { - fastuidraw::TessellatedPath::point P; + TessellatedPath::point P; P.m_p = pt; m_data.push_back(P); } - const fastuidraw::PathContour::interpolator_generic *m_h; - fastuidraw::TessellatedPath::TessellationParams m_thresh; + const interpolator_generic *m_h; + TessellationParams m_thresh; unsigned int m_max_recursion, m_max_size; - std::vector m_data; + std::vector m_data; }; class ArcTessellator { public: - ArcTessellator(const fastuidraw::ArcTessellatedPath::TessellationParams &tess_params, - const fastuidraw::PathContour::interpolator_generic *h): + typedef fastuidraw::PathContour PathContour; + typedef PathContour::interpolator_generic interpolator_generic; + typedef interpolator_generic::tessellated_region tessellated_region; + typedef fastuidraw::ArcTessellatedPath ArcTessellatedPath; + typedef ArcTessellatedPath::TessellationParams TessellationParams; + + ArcTessellator(const TessellationParams &tess_params, + const interpolator_generic *h): m_h(h), m_thresh(tess_params.m_threshhold), m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), @@ -100,25 +112,25 @@ namespace } unsigned int - dump(fastuidraw::c_array out_data, + dump(fastuidraw::c_array out_data, float *out_threshhold); private: void tessellation_worker(unsigned int recurse_level, - fastuidraw::PathContour::interpolator_generic::tessellated_region *in_L, - fastuidraw::PathContour::interpolator_generic::tessellated_region *in_R, + fastuidraw::reference_counted_ptr in_L, + fastuidraw::reference_counted_ptr in_R, fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, float *out_threshhold_sq); unsigned int - fill_data(fastuidraw::c_array out_data, + fill_data(fastuidraw::c_array out_data, float *out_threshhold); - const fastuidraw::PathContour::interpolator_generic *m_h; + const interpolator_generic *m_h; float m_thresh; unsigned int m_max_recursion, m_max_size; - std::vector m_data; + std::vector m_data; }; class InterpolatorBasePrivate @@ -189,7 +201,7 @@ namespace init(void); fastuidraw::vec2 m_min_bb, m_max_bb; - BezierTessRegion m_start_region; + fastuidraw::reference_counted_ptr m_start_region; std::vector m_pts; fastuidraw::vecN, 2> m_work_room; }; @@ -373,13 +385,12 @@ fill_data(fastuidraw::c_array out_data, void Tessellator:: tessellation_worker(unsigned int recurse_level, - fastuidraw::PathContour::interpolator_generic::tessellated_region *in_src, + fastuidraw::reference_counted_ptr in_src, float *out_threshhold) { using namespace fastuidraw; - PathContour::interpolator_generic::tessellated_region *rgnA(nullptr); - PathContour::interpolator_generic::tessellated_region *rgnB(nullptr); + reference_counted_ptr rgnA, rgnB; vec2 p; m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshhold); @@ -408,17 +419,6 @@ tessellation_worker(unsigned int recurse_level, { add_point(p); } - - - if (rgnA) - { - FASTUIDRAWdelete(rgnA); - } - - if (rgnB) - { - FASTUIDRAWdelete(rgnB); - } } /////////////////////////////////////// @@ -430,22 +430,12 @@ dump(fastuidraw::c_array out_data, { using namespace fastuidraw; - PathContour::interpolator_generic::tessellated_region *L, *R; + reference_counted_ptr L, R; vec2 mid; m_h->tessellate(nullptr, &L, &R, &mid, nullptr); tessellation_worker(1, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); - if (L) - { - FASTUIDRAWdelete(L); - } - - if (R) - { - FASTUIDRAWdelete(R); - } - FASTUIDRAWassert(m_data.size() <= out_data.size()); std::copy(m_data.begin(), m_data.end(), out_data.begin()); return m_data.size(); @@ -454,14 +444,13 @@ dump(fastuidraw::c_array out_data, void ArcTessellator:: tessellation_worker(unsigned int recurse_level, - fastuidraw::PathContour::interpolator_generic::tessellated_region *inL, - fastuidraw::PathContour::interpolator_generic::tessellated_region *inR, + fastuidraw::reference_counted_ptr inL, + fastuidraw::reference_counted_ptr inR, fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, float *out_threshhold) { using namespace fastuidraw; - PathContour::interpolator_generic::tessellated_region *L0(nullptr), *L1(nullptr); - PathContour::interpolator_generic::tessellated_region *R0(nullptr), *R1(nullptr); + reference_counted_ptr L0, L1, R0, R1; vec2 midL, midR; static float tol(0.00001f); @@ -509,23 +498,6 @@ tessellation_worker(unsigned int recurse_level, */ *out_threshhold = 0.0f; } - - if (L0) - { - FASTUIDRAWdelete(L0); - } - if (L1) - { - FASTUIDRAWdelete(L1); - } - if (R0) - { - FASTUIDRAWdelete(R0); - } - if (R1) - { - FASTUIDRAWdelete(R1); - } return; } @@ -559,23 +531,6 @@ tessellation_worker(unsigned int recurse_level, S.m_data.y() = std::atan2(end.y() - c.y(), end.x() - c.x()); m_data.push_back(S); } - - if (L0) - { - FASTUIDRAWdelete(L0); - } - if (L1) - { - FASTUIDRAWdelete(L1); - } - if (R0) - { - FASTUIDRAWdelete(R0); - } - if (R1) - { - FASTUIDRAWdelete(R1); - } } //////////////////////////////////////// @@ -600,7 +555,8 @@ init(void) m_max_bb.x() = fastuidraw::t_max(m_max_bb.x(), m_pts[i].x()); m_max_bb.y() = fastuidraw::t_max(m_max_bb.y(), m_pts[i].y()); } - m_start_region.m_pts = m_pts; //original region uses original points. + m_start_region = FASTUIDRAWnew BezierTessRegion(); + m_start_region->m_pts = m_pts; //original region uses original points. m_work_room[0].resize(m_pts.size()); m_work_room[1].resize(m_pts.size()); @@ -763,23 +719,24 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const void fastuidraw::PathContour::bezier:: -tessellate(tessellated_region *in_region, - tessellated_region **out_regionA, tessellated_region **out_regionB, +tessellate(reference_counted_ptr in_region, + reference_counted_ptr *out_regionA, + reference_counted_ptr *out_regionB, vec2 *out_p, float *out_threshhold) const { BezierPrivate *d; d = static_cast(m_d); - if (in_region == nullptr) + if (!in_region) { - in_region = &d->m_start_region; + in_region = d->m_start_region; } BezierTessRegion *in_region_casted; - FASTUIDRAWassert(dynamic_cast(in_region) != nullptr); - in_region_casted = static_cast(in_region); + FASTUIDRAWassert(dynamic_cast(in_region.get()) != nullptr); + in_region_casted = static_cast(in_region.get()); - BezierTessRegion *newA, *newB; + reference_counted_ptr newA, newB; newA = FASTUIDRAWnew BezierTessRegion(in_region_casted, true); newB = FASTUIDRAWnew BezierTessRegion(in_region_casted, false); @@ -1503,7 +1460,7 @@ PathPrivate(fastuidraw::Path *p, const PathPrivate &obj): /* if the last contour is not ended, we need to do a * deep copy on it. */ - if (!m_contours.back()->ended()) + if (!m_contours.empty() && !m_contours.back()->ended()) { m_contours.back() = m_contours.back()->deep_copy(); m_is_flat = m_is_flat && m_contours.back()->is_flat(); From 25e658ad7b148f5a79f97c866cf84c2e1e3eb71b Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 15:21:36 +0300 Subject: [PATCH 44/52] fastuidraw/path: tweaks for better arc-tessellation Change-Id: Icf87d3de91abc09202e9b5b7d36ffee4f8d558b3 --- inc/fastuidraw/path.hpp | 44 ++++++ src/fastuidraw/arc_tessellated_path.cpp | 9 +- src/fastuidraw/path.cpp | 142 +++++++++++++------ src/fastuidraw/private/path_util_private.cpp | 13 ++ src/fastuidraw/private/path_util_private.hpp | 3 + 5 files changed, 167 insertions(+), 44 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 2b6e92be8..6e0b11548 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -140,6 +140,15 @@ class PathContour: c_array out_data, float *out_threshhold) const = 0; + /*! + * To be implemented by a derived class to return a reasonable + * lower bound on the needed number of segments to capture the + * general shape when performing arc-tessellation. + */ + virtual + unsigned int + minimum_arc_tessellation_segments(void) const = 0; + /*! * To be implemented by a derived class to return a fast (and approximate) * bounding box for the interpolator. @@ -204,6 +213,10 @@ class PathContour: virtual interpolator_base* deep_copy(const reference_counted_ptr &prev) const; + + virtual + unsigned int + minimum_arc_tessellation_segments(void) const; }; /*! @@ -323,6 +336,10 @@ class PathContour: interpolator_base* deep_copy(const reference_counted_ptr &prev) const; + virtual + unsigned int + minimum_arc_tessellation_segments(void) const; + private: bezier(const bezier &q, const reference_counted_ptr &prev); @@ -385,6 +402,9 @@ class PathContour: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, c_array out_data, float *out_threshhold) const; + virtual + unsigned int + minimum_arc_tessellation_segments(void) const; private: arc(const arc &q, const reference_counted_ptr &prev); @@ -944,6 +964,30 @@ class Path const reference_counted_ptr& tessellation(void) const; + /*! + * Return the arc-tessellation of this Path at a specific + * level of detail. The ArcTessellatedPath is constructed + * lazily. Additionally, if this Path changes its geometry, + * then a new ArcTessellatedPath will be contructed on the + * next call to arc_tessellation(). + * \param thresh the returned tessellated path will be so that + * ArcTessellatedPath::effective_threshhold() + * is no more than thresh. A non-positive value + * will return the starting point tessellation. + */ + const reference_counted_ptr& + arc_tessellation(float thresh) const; + + /*! + * Provided as a conveniance, returns the starting point tessellation. + * Equivalent to + * \code + * arc_tessellation(-1.0f) + * \endcode + */ + const reference_counted_ptr& + arc_tessellation(void) const; + private: void *m_d; }; diff --git a/src/fastuidraw/arc_tessellated_path.cpp b/src/fastuidraw/arc_tessellated_path.cpp index 1bbe513f1..cf59ac126 100644 --- a/src/fastuidraw/arc_tessellated_path.cpp +++ b/src/fastuidraw/arc_tessellated_path.cpp @@ -109,7 +109,10 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, unsigned int needed; float tmp; - work_room.resize(m_params.m_max_segments + 1); + m_params.m_max_segments = t_max(TP.m_max_segments, + contour->interpolator(e)->minimum_arc_tessellation_segments()); + work_room.resize(m_params.m_max_segments); + temp.push_back(std::vector()); needed = contour->interpolator(e)->produce_tessellation(m_params, make_c_array(work_room), @@ -118,7 +121,7 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, loc += needed; FASTUIDRAWassert(needed > 0u); - m_max_segments = t_max(m_max_segments, needed - 1); + m_max_segments = t_max(m_max_segments, needed); m_effective_threshhold = t_max(m_effective_threshhold, tmp); work_room.resize(needed); @@ -189,6 +192,8 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, } FASTUIDRAWassert(total_needed == m_segment_data.size()); } + + m_params.m_max_segments = TP.m_max_segments; } ////////////////////////////////////// diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 292e47bf3..331be25e5 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -264,18 +264,20 @@ namespace class PathPrivate; + template class TessellatedPathList { public: - typedef fastuidraw::TessellatedPath TessellatedPath; - typedef fastuidraw::reference_counted_ptr tessellated_path_ref; + typedef pTessedClass TessedPath; + typedef typename TessedPath::TessellationParams TessParams; + typedef fastuidraw::reference_counted_ptr TessedPathRef; explicit TessellatedPathList(void): m_done(false) {} - const tessellated_path_ref& + const TessedPathRef& tessellation(const fastuidraw::Path &path, float thresh); void @@ -286,8 +288,25 @@ namespace } private: + class reverse_compare_thresh + { + public: + bool + operator()(const TessedPathRef &lhs, float rhs) const + { + return lhs->effective_threshhold() > rhs; + } + + bool + operator()(const TessedPathRef &lhs, + const TessedPathRef &rhs) const + { + return lhs->effective_threshhold() > rhs->effective_threshhold(); + } + }; + bool m_done; - std::vector m_data; + std::vector m_data; }; class PathPrivate:fastuidraw::noncopyable @@ -313,7 +332,8 @@ namespace clear_tesses(void); std::vector > m_contours; - TessellatedPathList m_tess_list; + TessellatedPathList m_tess_list; + TessellatedPathList m_arc_tess_list; /* m_start_check_bb gives the index into m_contours that * have not had their bounding box absorbed into @@ -324,23 +344,6 @@ namespace bool m_is_flat; fastuidraw::Path *m_p; }; - - class reverse_compare_thresh - { - public: - bool - operator()(const TessellatedPathList::tessellated_path_ref &lhs, float rhs) const - { - return lhs->effective_threshhold() > rhs; - } - - bool - operator()(const TessellatedPathList::tessellated_path_ref &lhs, - const TessellatedPathList::tessellated_path_ref &rhs) const - { - return lhs->effective_threshhold() > rhs->effective_threshhold(); - } - }; } ///////////////////////////////// @@ -493,10 +496,11 @@ tessellation_worker(unsigned int recurse_level, S.m_radius = 0.0f; m_data.push_back(S); - /* TODO: compute the distance of mid, midL and midR from - * the segment and use that as the output threshhold - */ - *out_threshhold = 0.0f; + *out_threshhold = t_max(detail::distance_to_line(p0, start, end), + detail::distance_to_line(p1, start, end)); + + *out_threshhold = t_max(*out_threshhold, + detail::distance_to_line(mid, start, end)); } return; } @@ -791,6 +795,16 @@ deep_copy(const reference_counted_ptr &prev) const return FASTUIDRAWnew bezier(*this, prev); } +unsigned int +fastuidraw::PathContour::bezier:: +minimum_arc_tessellation_segments(void) const +{ + BezierPrivate *d; + d = static_cast(m_d); + + return 2 * d->m_pts.size(); +} + ////////////////////////////////////// // fastuidraw::PathContour::flat methods bool @@ -857,6 +871,13 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const out_max_bb->y() = fastuidraw::t_max(p0.y(), p1.y()); } +unsigned int +fastuidraw::PathContour::flat:: +minimum_arc_tessellation_segments(void) const +{ + return 1; +} + ////////////////////////////////////// // fastuidraw::PathContour::arc methods fastuidraw::PathContour::arc:: @@ -1007,6 +1028,13 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, return 1; } +unsigned int +fastuidraw::PathContour::arc:: +minimum_arc_tessellation_segments(void) const +{ + return 1; +} + void fastuidraw::PathContour::arc:: approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const @@ -1343,15 +1371,16 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const ///////////////////////////////// // TessellatedPathList methods -const TessellatedPathList::tessellated_path_ref& -TessellatedPathList:: +template +const typename TessellatedPathList::TessedPathRef& +TessellatedPathList:: tessellation(const fastuidraw::Path &path, float thresh) { using namespace fastuidraw; if (m_data.empty()) { - TessellatedPath::TessellationParams params; + TessParams params; vec2 bb_min, bb_max, bb_size; /* always prefer to use distance threshholds over @@ -1369,7 +1398,7 @@ tessellation(const fastuidraw::Path &path, float thresh) params.threshhold(d / 500.0f); } } - m_data.push_back(FASTUIDRAWnew TessellatedPath(path, params)); + m_data.push_back(FASTUIDRAWnew TessedPath(path, params)); } if (thresh <= 0.0 || path.is_flat()) @@ -1379,7 +1408,7 @@ tessellation(const fastuidraw::Path &path, float thresh) if (m_data.back()->effective_threshhold() <= thresh) { - std::vector::const_iterator iter; + typename std::vector::const_iterator iter; iter = std::lower_bound(m_data.begin(), m_data.end(), thresh, @@ -1396,8 +1425,8 @@ tessellation(const fastuidraw::Path &path, float thresh) return m_data.back(); } - tessellated_path_ref prev_ref, ref; - TessellatedPath::TessellationParams params; + TessedPathRef prev_ref, ref; + TessParams params; ref = m_data.back(); params @@ -1406,16 +1435,28 @@ tessellation(const fastuidraw::Path &path, float thresh) while(!m_done && ref->effective_threshhold() > thresh) { + const int max_tries(6); + params.m_threshhold *= 0.5f; while(!m_done && ref->effective_threshhold() > params.m_threshhold) { float last_tess; + int no_improve_count; + no_improve_count = 0; params.m_max_segments *= 2; last_tess = ref->effective_threshhold(); - ref = FASTUIDRAWnew TessellatedPath(path, params); - if (last_tess > ref->effective_threshhold()) + ref = FASTUIDRAWnew TessedPath(path, params); + + while (last_tess <= ref->effective_threshhold() && no_improve_count < max_tries) + { + params.m_max_segments *= 2; + ref = FASTUIDRAWnew TessedPath(path, params); + ++no_improve_count; + } + + if (no_improve_count < max_tries) { m_data.push_back(ref); } @@ -1423,13 +1464,12 @@ tessellation(const fastuidraw::Path &path, float thresh) { m_done = true; - /* - *std::cout << "Tapped out on type = (max_segs = " - * << ref->max_segments() << ", tess_factor = " - * << ref->effective_threshhold(m_type) - * << ", num_points = " << ref->point_data().size() - * << ")\n"; - */ + /**/ + std::cout << "Tapped out on type = (max_segs = " + << ref->max_segments() << ", tess_factor = " + << ref->effective_threshhold() + << ")\n"; + /**/ } } } @@ -1451,6 +1491,7 @@ PathPrivate:: PathPrivate(fastuidraw::Path *p, const PathPrivate &obj): m_contours(obj.m_contours), m_tess_list(obj.m_tess_list), + m_arc_tess_list(obj.m_arc_tess_list), m_start_check_bb(obj.m_start_check_bb), m_max_bb(obj.m_max_bb), m_min_bb(obj.m_min_bb), @@ -1485,6 +1526,7 @@ PathPrivate:: clear_tesses(void) { m_tess_list.clear(); + m_arc_tess_list.clear(); } ///////////////////////////////////////// @@ -1685,6 +1727,22 @@ tessellation(float thresh) const return d->m_tess_list.tessellation(*this, thresh); } +const fastuidraw::reference_counted_ptr& +fastuidraw::Path:: +arc_tessellation(void) const +{ + return arc_tessellation(-1.0f); +} + +const fastuidraw::reference_counted_ptr& +fastuidraw::Path:: +arc_tessellation(float thresh) const +{ + PathPrivate *d; + d = static_cast(m_d); + return d->m_arc_tess_list.tessellation(*this, thresh); +} + bool fastuidraw::Path:: approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const diff --git a/src/fastuidraw/private/path_util_private.cpp b/src/fastuidraw/private/path_util_private.cpp index 1ef1a3e29..6dbe02024 100644 --- a/src/fastuidraw/private/path_util_private.cpp +++ b/src/fastuidraw/private/path_util_private.cpp @@ -54,3 +54,16 @@ number_segments_for_tessellation(float arc_angle, float distance_thresh) */ return 1 + fastuidraw::t_max(3u, static_cast(needed_sizef)); } + +float +fastuidraw::detail:: +distance_to_line(const vec2 &q, const vec2 &p1, const vec2 &p2) +{ + vec2 delta(p2 - p1); + float num, den; + + num = delta.y() * q.x() - delta.x() * q.y() - p2.x() * p1.y() - p1.x() * p2.y(); + den = delta.magnitudeSq(); + + return t_sqrt(num / den); +} diff --git a/src/fastuidraw/private/path_util_private.hpp b/src/fastuidraw/private/path_util_private.hpp index 0eda81440..676ae9a48 100644 --- a/src/fastuidraw/private/path_util_private.hpp +++ b/src/fastuidraw/private/path_util_private.hpp @@ -31,5 +31,8 @@ namespace fastuidraw unsigned int number_segments_for_tessellation(float arc_angle, float distance_thresh); + + float + distance_to_line(const vec2 &q, const vec2 &p0, const vec2 &p1); } } From 04339d09a64e4f19094b7edaf1772c0b22385b01 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 15:59:57 +0300 Subject: [PATCH 45/52] fastuidraw/path: change arc tessellation inteface to take an abstract storage class Change the arc-tessellaion methods to take an abstract storage class, this way the number of elements needed for tessellation is not needed to be known before starting. Change-Id: I0f3efc9888710dacecf12eb9350375f7e5022714 --- inc/fastuidraw/arc_tessellated_path.hpp | 24 ++++++ inc/fastuidraw/path.hpp | 16 ++-- src/fastuidraw/arc_tessellated_path.cpp | 101 +++++++++++++----------- src/fastuidraw/path.cpp | 81 +++++++++---------- 4 files changed, 127 insertions(+), 95 deletions(-) diff --git a/inc/fastuidraw/arc_tessellated_path.hpp b/inc/fastuidraw/arc_tessellated_path.hpp index cb04df0a3..f4b6229d8 100644 --- a/inc/fastuidraw/arc_tessellated_path.hpp +++ b/inc/fastuidraw/arc_tessellated_path.hpp @@ -206,6 +206,30 @@ class ArcTessellatedPath: float m_closed_contour_length; }; + /*! + * \brief + * A wrapper over a dynamic array of \ref segment objects; + * segment values added to SegmentStorage must be added + * in order of time along the domain of a \ref + * PathContour::interpolate_base + */ + class SegmentStorage:fastuidraw::noncopyable + { + public: + /*! + * Add a \ref segment to the SegmentStorage. + */ + void + add_segment(const segment&); + + private: + SegmentStorage(void) {} + ~SegmentStorage() {} + + friend class ArcTessellatedPath; + void *m_d; + }; + /*! * Ctor. Construct a TessellatedPath from a Path * \param input source path to tessellate diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 6e0b11548..2b9157ec2 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -135,9 +135,9 @@ class PathContour: * approximation. */ virtual - unsigned int + void produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const = 0; /*! @@ -202,9 +202,9 @@ class PathContour: c_array out_data, float *out_threshholds) const; virtual - unsigned int + void produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; virtual void @@ -253,9 +253,9 @@ class PathContour: c_array out_data, float *out_threshholds) const; virtual - unsigned int + void produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; /*! @@ -398,9 +398,9 @@ class PathContour: c_array out_data, float *out_threshholds) const; virtual - unsigned int + void produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; virtual unsigned int diff --git a/src/fastuidraw/arc_tessellated_path.cpp b/src/fastuidraw/arc_tessellated_path.cpp index cf59ac126..d5c45d987 100644 --- a/src/fastuidraw/arc_tessellated_path.cpp +++ b/src/fastuidraw/arc_tessellated_path.cpp @@ -89,45 +89,66 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, m_effective_threshhold(0.0f), m_max_segments(0u) { - using namespace fastuidraw; +} + +////////////////////////////////////////////////////////// +// fastuidraw::ArcTessellatedPath::SegmentStorage methods +void +fastuidraw::ArcTessellatedPath::SegmentStorage:: +add_segment(const segment &S) +{ + std::vector *d; + d = static_cast*>(m_d); + d->push_back(S); +} + +////////////////////////////////////// +// fastuidraw::ArcTessellatedPath methods +fastuidraw::ArcTessellatedPath:: +ArcTessellatedPath(const Path &input, + fastuidraw::ArcTessellatedPath::TessellationParams TP) +{ + ArcTessellatedPathPrivate *d; + m_d = d = FASTUIDRAWnew ArcTessellatedPathPrivate(input, TP); if (input.number_contours() > 0) { - std::list > temp; - std::vector work_room; - std::list >::const_iterator iter, end_iter; + std::list > temp; + std::vector work_room; + std::list >::const_iterator iter, end_iter; for(unsigned int loc = 0, o = 0, endo = input.number_contours(); o < endo; ++o) { reference_counted_ptr contour(input.contour(o)); float contour_length(0.0f), open_contour_length(0.0f), closed_contour_length(0.0f); - std::list >::iterator start_contour; + std::list >::iterator start_contour; - m_edge_ranges[o].resize(contour->number_points()); + d->m_edge_ranges[o].resize(contour->number_points()); for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) { unsigned int needed; float tmp; + SegmentStorage segment_storage; + + d->m_params.m_max_segments = t_max(TP.m_max_segments, + contour->interpolator(e)->minimum_arc_tessellation_segments()); + FASTUIDRAWassert(work_room.empty()); + segment_storage.m_d = &work_room; - m_params.m_max_segments = t_max(TP.m_max_segments, - contour->interpolator(e)->minimum_arc_tessellation_segments()); - work_room.resize(m_params.m_max_segments); + contour->interpolator(e)->produce_tessellation(d->m_params, &segment_storage, &tmp); - temp.push_back(std::vector()); - needed = contour->interpolator(e)->produce_tessellation(m_params, - make_c_array(work_room), - &tmp); - m_edge_ranges[o][e] = range_type(loc, loc + needed); + needed = work_room.size(); + d->m_edge_ranges[o][e] = range_type(loc, loc + needed); loc += needed; FASTUIDRAWassert(needed > 0u); - m_max_segments = t_max(m_max_segments, needed); - m_effective_threshhold = t_max(m_effective_threshhold, tmp); + d->m_max_segments = t_max(d->m_max_segments, needed); + d->m_effective_threshhold = t_max(d->m_effective_threshhold, tmp); work_room.resize(needed); for(unsigned int n = 0; n < work_room.size(); ++n) { - union_segment(work_room[n], m_bounding_box); + union_segment(work_room[n], d->m_bounding_box); work_room[n].m_length = segment_length(work_room[n]); if (n != 0) @@ -141,20 +162,16 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, work_room[n].m_distance_from_edge_start = 0.0f; } - work_room[n].m_distance_from_contour_start - = contour_length + work_room[n].m_distance_from_edge_start; + work_room[n].m_distance_from_contour_start = contour_length; + contour_length += work_room[n].m_distance_from_edge_start; } - std::list >::iterator t; - t = temp.insert(temp.end(), work_room); - if (e == 0) + for(unsigned int n = 0; n < needed; ++n) { - start_contour = t; + work_room[n].m_edge_length = work_room[needed - 1].m_distance_from_edge_start + + work_room[needed - 1].m_length; } - contour_length = temp.back().back().m_distance_from_contour_start - + temp.back().back().m_length; - if (e + 2 == ende) { open_contour_length = contour_length; @@ -164,14 +181,18 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, closed_contour_length = contour_length; } - for(unsigned int n = 0; n < needed; ++n) + /* append the data to temp and clear work_room for the next edge */ + std::list >::iterator t; + t = temp.insert(temp.end(), std::vector()); + t->swap(work_room); + + if (e == 0) { - (*t)[n].m_edge_length = (*t)[needed - 1].m_distance_from_edge_start - + (*t)[needed - 1].m_length; + start_contour = t; } } - for(std::list >::iterator + for(std::list >::iterator t = start_contour, endt = temp.end(); t != endt; ++t) { for(unsigned int e = 0, ende = t->size(); e < ende; ++e) @@ -184,26 +205,16 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, unsigned int total_needed; - total_needed = m_edge_ranges.back().back().m_end; - m_segment_data.reserve(total_needed); + total_needed = d->m_edge_ranges.back().back().m_end; + d->m_segment_data.reserve(total_needed); for(iter = temp.begin(), end_iter = temp.end(); iter != end_iter; ++iter) { - std::copy(iter->begin(), iter->end(), std::back_inserter(m_segment_data)); + std::copy(iter->begin(), iter->end(), std::back_inserter(d->m_segment_data)); } - FASTUIDRAWassert(total_needed == m_segment_data.size()); + FASTUIDRAWassert(total_needed == d->m_segment_data.size()); } - m_params.m_max_segments = TP.m_max_segments; -} - -////////////////////////////////////// -// fastuidraw::ArcTessellatedPath methods -fastuidraw::ArcTessellatedPath:: -ArcTessellatedPath(const Path &input, - fastuidraw::ArcTessellatedPath::TessellationParams TP) -{ - ArcTessellatedPathPrivate *d; - m_d = d = FASTUIDRAWnew ArcTessellatedPathPrivate(input, TP); + d->m_params.m_max_segments = TP.m_max_segments; } fastuidraw::ArcTessellatedPath:: diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 331be25e5..13c3677db 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -111,26 +111,22 @@ namespace { } - unsigned int - dump(fastuidraw::c_array out_data, - float *out_threshhold); + void + dump(ArcTessellatedPath::SegmentStorage *out_data, + float *out_threshhold) const; private: void tessellation_worker(unsigned int recurse_level, + ArcTessellatedPath::SegmentStorage *out_data, fastuidraw::reference_counted_ptr in_L, fastuidraw::reference_counted_ptr in_R, fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, - float *out_threshhold_sq); - - unsigned int - fill_data(fastuidraw::c_array out_data, - float *out_threshhold); + float *out_threshhold) const; const interpolator_generic *m_h; float m_thresh; unsigned int m_max_recursion, m_max_size; - std::vector m_data; }; class InterpolatorBasePrivate @@ -426,10 +422,10 @@ tessellation_worker(unsigned int recurse_level, /////////////////////////////////////// // ArcTessellator methods -unsigned int +void ArcTessellator:: -dump(fastuidraw::c_array out_data, - float *out_threshhold) +dump(ArcTessellatedPath::SegmentStorage *out_data, + float *out_threshhold) const { using namespace fastuidraw; @@ -437,20 +433,17 @@ dump(fastuidraw::c_array out_data, vec2 mid; m_h->tessellate(nullptr, &L, &R, &mid, nullptr); - tessellation_worker(1, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); - - FASTUIDRAWassert(m_data.size() <= out_data.size()); - std::copy(m_data.begin(), m_data.end(), out_data.begin()); - return m_data.size(); + tessellation_worker(1, out_data, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); } void ArcTessellator:: tessellation_worker(unsigned int recurse_level, + ArcTessellatedPath::SegmentStorage *out_data, fastuidraw::reference_counted_ptr inL, fastuidraw::reference_counted_ptr inR, fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, - float *out_threshhold) + float *out_threshhold) const { using namespace fastuidraw; reference_counted_ptr L0, L1, R0, R1; @@ -479,9 +472,9 @@ tessellation_worker(unsigned int recurse_level, { if (recurse_level + 1u < m_max_recursion) { - tessellation_worker(recurse_level + 1u, L0, L1, + tessellation_worker(recurse_level + 1u, out_data, L0, L1, start, midL, mid, &threshL); - tessellation_worker(recurse_level + 1u, R0, R1, + tessellation_worker(recurse_level + 1u, out_data, R0, R1, mid, midR, end, &threshR); *out_threshhold = t_max(threshL, threshR); } @@ -494,7 +487,7 @@ tessellation_worker(unsigned int recurse_level, S.m_p = start; S.m_data = end; S.m_radius = 0.0f; - m_data.push_back(S); + out_data->add_segment(S); *out_threshhold = t_max(detail::distance_to_line(p0, start, end), detail::distance_to_line(p1, start, end)); @@ -517,9 +510,9 @@ tessellation_worker(unsigned int recurse_level, if (recurse_level + 1u < m_max_recursion && *out_threshhold > m_thresh) { - tessellation_worker(recurse_level + 1u, L0, L1, + tessellation_worker(recurse_level + 1u, out_data, L0, L1, start, midL, mid, &threshL); - tessellation_worker(recurse_level + 1u, R0, R1, + tessellation_worker(recurse_level + 1u, out_data, R0, R1, mid, midR, end, &threshR); *out_threshhold = t_max(threshL, threshR); } @@ -533,7 +526,7 @@ tessellation_worker(unsigned int recurse_level, S.m_data.x() = std::atan2(start.y() - c.y(), start.x() - c.x()); S.m_data.y() = std::atan2(end.y() - c.y(), end.x() - c.x()); - m_data.push_back(S); + out_data->add_segment(S); } } @@ -626,14 +619,14 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, return tesser.dump(out_data, out_threshhold); } -unsigned int +void fastuidraw::PathContour::interpolator_generic:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const { ArcTessellator tesser(tess_params, this); - return tesser.dump(out_data, out_threshhold); + tesser.dump(out_data, out_threshhold); } //////////////////////////////////// @@ -834,20 +827,23 @@ produce_tessellation(const TessellatedPath::TessellationParams&, return 2; } -unsigned int +void fastuidraw::PathContour::flat:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const { FASTUIDRAWunused(tess_params); - out_data[0].m_type = ArcTessellatedPath::line_segment; - out_data[0].m_p = start_pt(); - out_data[0].m_data = end_pt(); - out_data[0].m_radius = 0.0f; + + ArcTessellatedPath::segment S; + + S.m_type = ArcTessellatedPath::line_segment; + S.m_p = start_pt(); + S.m_data = end_pt(); + S.m_radius = 0.0f; + out_data->add_segment(S); *out_threshhold = 0.0f; - return 1; } fastuidraw::PathContour::interpolator_base* @@ -1008,24 +1004,25 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, return return_value; } -unsigned int +void fastuidraw::PathContour::arc:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, - c_array out_data, + ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const { ArcPrivate *d; + ArcTessellatedPath::segment S; d = static_cast(m_d); FASTUIDRAWunused(tess_params); - out_data[0].m_type = ArcTessellatedPath::arc_segment; - out_data[0].m_p = d->m_center; - out_data[0].m_data.x() = d->m_start_angle; - out_data[0].m_data.y() = d->m_start_angle + d->m_angle_speed; - out_data[0].m_radius = d->m_radius; + S.m_type = ArcTessellatedPath::arc_segment; + S.m_p = d->m_center; + S.m_data.x() = d->m_start_angle; + S.m_data.y() = d->m_start_angle + d->m_angle_speed; + S.m_radius = d->m_radius; + out_data->add_segment(S); *out_threshhold = 0.0f; - return 1; } unsigned int From f9aa94700f060704e90d5896536ecdbdd328c77a Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 16:28:06 +0300 Subject: [PATCH 46/52] fastuidraw/path: change tessellation inteface to take an abstract storage class Change the tessellaion methods to take an abstract storage class, this way the number of elements needed for tessellation is not needed to be known before starting. Change-Id: Ice7a0b214fd46933c49f5df3cca0a2f478fbd8c9 --- inc/fastuidraw/path.hpp | 26 +++--- inc/fastuidraw/tessellated_path.hpp | 24 ++++++ src/fastuidraw/path.cpp | 123 +++++++++++++--------------- src/fastuidraw/tessellated_path.cpp | 98 ++++++++++++---------- 4 files changed, 146 insertions(+), 125 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 2b9157ec2..1cbf7e87d 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -102,10 +102,8 @@ class PathContour: * To be implemented by a derived class to produce the tessellation * from start_pt() to end_pt(). The routine must include BOTH start_pt() * and end_pt() in the result. Only the fields TessellatedPath::point::m_p, - * and TessellatedPath::point::m_distance_from_edge_start are to be filled; - * the other fields of TessellatedPath::point are filled by TessellatedPath. - * In addition to filling the output array, the function shall return the - * number of points needed to perform the required tessellation. + * and are to be filled; the other fields of TessellatedPath::point are + * filled by TessellatedPath. * * \param tess_params tessellation parameters * \param out_data location to which to write the edge tessellated @@ -114,19 +112,17 @@ class PathContour: * approximation. */ virtual - unsigned int + void produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshhold) const = 0; /*! * To be implemented by a derived class to produce the arc-tessellation * from start_pt() to end_pt(). Only the fields ArcTessellatedPath::segment::m_p, * and ArcTessellatedPath::m_type, ArcTessellatedPath::m_data and - * ArcTessellatedPath::m_data are to be filled; the other fields of + * ArcTessellatedPath::m_radius are to be filled; the other fields of * ArcTessellatedPath::segment are filled by ArcTessellatedPath. - * In addition to filling the output array, the function shall return the - * number of segments needed to perform the required tessellation. * * \param tess_params tessellation parameters * \param out_data location to which to write the tessellation @@ -197,9 +193,9 @@ class PathContour: is_flat(void) const; virtual - unsigned int + void produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual void @@ -248,9 +244,9 @@ class PathContour: {} virtual - unsigned int + void produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual void @@ -393,9 +389,9 @@ class PathContour: deep_copy(const reference_counted_ptr &prev) const; virtual - unsigned int + void produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual void diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index dd665f364..48f1468b3 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -175,6 +175,30 @@ class TessellatedPath: float m_closed_contour_length; }; + /*! + * \brief + * A wrapper over a dynamic array of \ref segment objects; + * segment values added to SegmentStorage must be added + * in order of time along the domain of a \ref + * PathContour::interpolate_base + */ + class PointStorage:fastuidraw::noncopyable + { + public: + /*! + * Add a \ref point to the PointStorage. + */ + void + add_point(const point&); + + private: + PointStorage(void) {} + ~PointStorage() {} + + friend class TessellatedPath; + void *m_d; + }; + /*! * Ctor. Construct a TessellatedPath from a Path * \param input source path to tessellate diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 13c3677db..32d8f31af 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -65,32 +65,29 @@ namespace { } - unsigned int - dump(fastuidraw::c_array out_data, - float *out_threshhold); + void + dump(TessellatedPath::PointStorage *out_data, + float *out_threshhold) const; private: void tessellation_worker(unsigned int recurse_level, + TessellatedPath::PointStorage *out_data, fastuidraw::reference_counted_ptr in_src, - float *out_threshhold); - - unsigned int - fill_data(fastuidraw::c_array out_data, - float *out_threshhold); + float *out_threshhold) const; void - add_point(const fastuidraw::vec2 &pt) + add_point(TessellatedPath::PointStorage *out_data, + const fastuidraw::vec2 &pt) const { TessellatedPath::point P; P.m_p = pt; - m_data.push_back(P); + out_data->add_point(P); } const interpolator_generic *m_h; TessellationParams m_thresh; unsigned int m_max_recursion, m_max_size; - std::vector m_data; }; class ArcTessellator @@ -344,48 +341,28 @@ namespace ///////////////////////////////// // Tessellator methods -unsigned int +void Tessellator:: -dump(fastuidraw::c_array out_data, - float *out_threshhold) +dump(TessellatedPath::PointStorage *out_data, + float *out_threshhold) const { - unsigned int return_value; - *out_threshhold = -1.0f; - return_value = fill_data(out_data, out_threshhold); - out_data = out_data.sub_array(0, return_value); - - /* enforce start and end point values */ - out_data.front().m_p = m_h->start_pt(); - out_data.back().m_p = m_h->end_pt(); - - return return_value; -} - -unsigned int -Tessellator:: -fill_data(fastuidraw::c_array out_data, - float *out_threshhold) -{ /* * tessellate: note that we add the start point, then tessellate * and then at the end add the end point. By doing so, the points * are added to m_data in order of time automatically. */ - add_point(m_h->start_pt()); - tessellation_worker(0, nullptr, out_threshhold); - add_point(m_h->end_pt()); - - FASTUIDRAWassert(m_data.size() <= out_data.size()); - std::copy(m_data.begin(), m_data.end(), out_data.begin()); - return m_data.size(); + add_point(out_data, m_h->start_pt()); + tessellation_worker(0, out_data, nullptr, out_threshhold); + add_point(out_data, m_h->end_pt()); } void Tessellator:: tessellation_worker(unsigned int recurse_level, + TessellatedPath::PointStorage *out_data, fastuidraw::reference_counted_ptr in_src, - float *out_threshhold) + float *out_threshhold) const { using namespace fastuidraw; @@ -408,15 +385,15 @@ tessellation_worker(unsigned int recurse_level, * mid point, and all points in the right side come * after the midpoint. */ - tessellation_worker(recurse_level + 1, rgnA, &tmpA); - add_point(p); - tessellation_worker(recurse_level + 1, rgnB, &tmpB); + tessellation_worker(recurse_level + 1, out_data, rgnA, &tmpA); + add_point(out_data, p); + tessellation_worker(recurse_level + 1, out_data, rgnB, &tmpB); *out_threshhold = t_max(tmpA, tmpB); } else { - add_point(p); + add_point(out_data, p); } } @@ -609,14 +586,14 @@ end_pt(void) const ////////////////////////////////////////////// // fastuidraw::PathContour::interpolator_generic methods -unsigned int +void fastuidraw::PathContour::interpolator_generic:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshhold) const { Tessellator tesser(tess_params, this); - return tesser.dump(out_data, out_threshhold); + tesser.dump(out_data, out_threshhold); } void @@ -807,24 +784,25 @@ is_flat(void) const return true; } -unsigned int +void fastuidraw::PathContour::flat:: produce_tessellation(const TessellatedPath::TessellationParams&, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshhold) const { + TessellatedPath::point p0, p1; vec2 delta(end_pt() - start_pt()); float mag(delta.magnitude()); - out_data[0].m_p = start_pt(); - out_data[0].m_distance_from_edge_start = 0.0f; + p0.m_p = start_pt(); + p0.m_distance_from_edge_start = 0.0f; + out_data->add_point(p0); - out_data[1].m_p = end_pt(); - out_data[1].m_distance_from_edge_start = mag; + p1.m_p = end_pt(); + p1.m_distance_from_edge_start = mag; + out_data->add_point(p1); *out_threshhold = 0.0f; - - return 2; } void @@ -970,16 +948,15 @@ is_flat(void) const return false; } -unsigned int +void fastuidraw::PathContour::arc:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, - c_array out_data, + TessellatedPath::PointStorage *out_data, float *out_threshhold) const { ArcPrivate *d; d = static_cast(m_d); - unsigned int return_value; - float s, c, a, da; + float a, da; unsigned int needed_size; float delta_angle; @@ -990,18 +967,30 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, da = 0.0f; for(unsigned int i = 0; i <= needed_size; ++i, a += delta_angle, da += delta_angle) { - s = d->m_radius * std::sin(a); - c = d->m_radius * std::cos(a); - out_data[i].m_p = d->m_center + vec2(c, s); - out_data[i].m_distance_from_edge_start = t_abs(da) * d->m_radius; + TessellatedPath::point p; + + if (i == 0) + { + p.m_p = start_pt(); + } + else if (i == needed_size) + { + p.m_p = end_pt(); + } + else + { + float c, s; + + c = d->m_radius * std::cos(a); + s = d->m_radius * std::sin(a); + p.m_p = d->m_center + vec2(c, s); + } + + p.m_distance_from_edge_start = t_abs(da) * d->m_radius; + out_data->add_point(p); } - out_data[0].m_p = start_pt(); - out_data[needed_size].m_p = end_pt(); *out_threshhold = d->m_radius * (1.0f - t_cos(delta_angle * 0.5f)); - - return_value = needed_size + 1; - return return_value; } void diff --git a/src/fastuidraw/tessellated_path.cpp b/src/fastuidraw/tessellated_path.cpp index afbeb6959..a5d7c0ff7 100644 --- a/src/fastuidraw/tessellated_path.cpp +++ b/src/fastuidraw/tessellated_path.cpp @@ -55,68 +55,87 @@ TessellatedPathPrivate(const fastuidraw::Path &input, m_effective_threshhold(0.0f), m_max_segments(0u) { - using namespace fastuidraw; +} + +////////////////////////////////////////////////////////// +// fastuidraw::TessellatedPath::PointStorage methods +void +fastuidraw::TessellatedPath::PointStorage:: +add_point(const point &p) +{ + std::vector *d; + d = static_cast*>(m_d); + d->push_back(p); +} + +////////////////////////////////////// +// fastuidraw::TessellatedPath methods +fastuidraw::TessellatedPath:: +TessellatedPath(const Path &input, + fastuidraw::TessellatedPath::TessellationParams TP) +{ + TessellatedPathPrivate *d; + m_d = d = FASTUIDRAWnew TessellatedPathPrivate(input, TP); if (input.number_contours() > 0) { - std::list > temp; - std::vector work_room; - std::list >::const_iterator iter, end_iter; + std::list > temp; + std::vector work_room; + std::list >::const_iterator iter, end_iter; for(unsigned int loc = 0, o = 0, endo = input.number_contours(); o < endo; ++o) { reference_counted_ptr contour(input.contour(o)); float contour_length(0.0f), open_contour_length(0.0f), closed_contour_length(0.0f); - std::list >::iterator start_contour; + std::list >::iterator start_contour; - m_edge_ranges[o].resize(contour->number_points()); + d->m_edge_ranges[o].resize(contour->number_points()); for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) { unsigned int needed; float tmp; + PointStorage point_storage; - work_room.resize(m_params.m_max_segments + 1); - temp.push_back(std::vector()); - needed = contour->interpolator(e)->produce_tessellation(m_params, - make_c_array(work_room), - &tmp); - m_edge_ranges[o][e] = range_type(loc, loc + needed); + FASTUIDRAWassert(work_room.empty()); + point_storage.m_d = &work_room; + contour->interpolator(e)->produce_tessellation(d->m_params, &point_storage, &tmp); + + needed = work_room.size(); + d->m_edge_ranges[o][e] = range_type(loc, loc + needed); loc += needed; FASTUIDRAWassert(needed > 0u); - m_max_segments = t_max(m_max_segments, needed - 1); - m_effective_threshhold = t_max(m_effective_threshhold, tmp); + d->m_max_segments = t_max(d->m_max_segments, needed - 1); + d->m_effective_threshhold = t_max(d->m_effective_threshhold, tmp); - work_room.resize(needed); for(unsigned int n = 0; n < work_room.size(); ++n) { - m_bounding_box.union_point(work_room[n].m_p); + d->m_bounding_box.union_point(work_room[n].m_p); if (n != 0) { vec2 delta; + float l; + delta = work_room[n].m_p - work_room[n - 1].m_p; - work_room[n].m_distance_from_edge_start = delta.magnitude() - + work_room[n - 1].m_distance_from_edge_start; + l = delta.magnitude(); + + work_room[n].m_distance_from_edge_start = l + work_room[n - 1].m_distance_from_edge_start; + contour_length += l; } else { work_room[n].m_distance_from_edge_start = 0.0f; } - work_room[n].m_distance_from_contour_start - = contour_length + work_room[n].m_distance_from_edge_start; + work_room[n].m_distance_from_contour_start = contour_length; } - std::list >::iterator t; - t = temp.insert(temp.end(), work_room); - if (e == 0) + for(unsigned int n = 0; n < needed; ++n) { - start_contour = t; + work_room[n].m_edge_length = work_room[needed - 1].m_distance_from_edge_start; } - contour_length = temp.back().back().m_distance_from_contour_start; - if (e + 2 == ende) { open_contour_length = contour_length; @@ -126,13 +145,16 @@ TessellatedPathPrivate(const fastuidraw::Path &input, closed_contour_length = contour_length; } - for(unsigned int n = 0; n < needed; ++n) + std::list >::iterator t; + t = temp.insert(temp.end(), std::vector()); + t->swap(work_room); + if (e == 0) { - (*t)[n].m_edge_length = (*t)[needed - 1].m_distance_from_edge_start; + start_contour = t; } } - for(std::list >::iterator + for(std::list >::iterator t = start_contour, endt = temp.end(); t != endt; ++t) { for(unsigned int e = 0, ende = t->size(); e < ende; ++e) @@ -145,26 +167,16 @@ TessellatedPathPrivate(const fastuidraw::Path &input, unsigned int total_needed; - total_needed = m_edge_ranges.back().back().m_end; - m_point_data.reserve(total_needed); + total_needed = d->m_edge_ranges.back().back().m_end; + d->m_point_data.reserve(total_needed); for(iter = temp.begin(), end_iter = temp.end(); iter != end_iter; ++iter) { - std::copy(iter->begin(), iter->end(), std::back_inserter(m_point_data)); + std::copy(iter->begin(), iter->end(), std::back_inserter(d->m_point_data)); } - FASTUIDRAWassert(total_needed == m_point_data.size()); + FASTUIDRAWassert(total_needed == d->m_point_data.size()); } } -////////////////////////////////////// -// fastuidraw::TessellatedPath methods -fastuidraw::TessellatedPath:: -TessellatedPath(const Path &input, - fastuidraw::TessellatedPath::TessellationParams TP) -{ - TessellatedPathPrivate *d; - m_d = d = FASTUIDRAWnew TessellatedPathPrivate(input, TP); -} - fastuidraw::TessellatedPath:: ~TessellatedPath() { From 00a5142b2a725c7e12016ed09739c7587daf2127 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 16:45:43 +0300 Subject: [PATCH 47/52] fastuidraw/path: use recursion limits instead of segment limits Change-Id: I11f0f200f7a2cf8da7552c7f236f45c4c405a268 --- inc/fastuidraw/arc_tessellated_path.hpp | 25 +++------- inc/fastuidraw/path.hpp | 12 ++--- inc/fastuidraw/tessellated_path.hpp | 28 ++++------- src/fastuidraw/arc_tessellated_path.cpp | 4 -- src/fastuidraw/path.cpp | 50 +++++++++++--------- src/fastuidraw/private/path_util_private.cpp | 13 +---- 6 files changed, 48 insertions(+), 84 deletions(-) diff --git a/inc/fastuidraw/arc_tessellated_path.hpp b/inc/fastuidraw/arc_tessellated_path.hpp index f4b6229d8..0f746cb7f 100644 --- a/inc/fastuidraw/arc_tessellated_path.hpp +++ b/inc/fastuidraw/arc_tessellated_path.hpp @@ -79,20 +79,9 @@ class ArcTessellatedPath: */ TessellationParams(void): m_threshhold(1.0f), - m_max_segments(32) + m_max_recursion(5) {} - /*! - * Non-equal comparison operator. - * \param rhs value to which to compare against - */ - bool - operator!=(const TessellationParams &rhs) const - { - return m_threshhold != rhs.m_threshhold - || m_max_segments != rhs.m_max_segments; - } - /*! * Provided as a conveniance. Equivalent to * \code @@ -112,24 +101,22 @@ class ArcTessellatedPath: * \param v value to which to assign to \ref m_max_segments */ TessellationParams& - max_segments(unsigned int v) + max_recursion(unsigned int v) { - m_max_segments = v; + m_max_recursion = v; return *this; } /*! - * Meaning depends on \ref m_threshhold_type. * Default value is 1.0. */ float m_threshhold; /*! - * Maximum number of segments to tessellate each - * PathContour::interpolator_base from each - * PathContour of a Path. Default value is 32. + * Maximum number of times to cut a single edge in + * half. Default value is 5. */ - unsigned int m_max_segments; + unsigned int m_max_recursion; }; /*! diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 1cbf7e87d..50b61df1b 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -138,12 +138,12 @@ class PathContour: /*! * To be implemented by a derived class to return a reasonable - * lower bound on the needed number of segments to capture the - * general shape when performing arc-tessellation. + * lower bound on the needed number of times the edge should be + * cut in half in order to capture its shape. */ virtual unsigned int - minimum_arc_tessellation_segments(void) const = 0; + minimum_arc_tessellation_recursion(void) const = 0; /*! * To be implemented by a derived class to return a fast (and approximate) @@ -212,7 +212,7 @@ class PathContour: virtual unsigned int - minimum_arc_tessellation_segments(void) const; + minimum_arc_tessellation_recursion(void) const; }; /*! @@ -334,7 +334,7 @@ class PathContour: virtual unsigned int - minimum_arc_tessellation_segments(void) const; + minimum_arc_tessellation_recursion(void) const; private: bezier(const bezier &q, @@ -400,7 +400,7 @@ class PathContour: float *out_threshhold) const; virtual unsigned int - minimum_arc_tessellation_segments(void) const; + minimum_arc_tessellation_recursion(void) const; private: arc(const arc &q, const reference_counted_ptr &prev); diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index 48f1468b3..3f0a99619 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -72,20 +72,9 @@ class TessellatedPath: */ TessellationParams(void): m_threshhold(1.0f), - m_max_segments(32) + m_max_recursion(5) {} - /*! - * Non-equal comparison operator. - * \param rhs value to which to compare against - */ - bool - operator!=(const TessellationParams &rhs) const - { - return m_threshhold != rhs.m_threshhold - || m_max_segments != rhs.m_max_segments; - } - /*! * Provided as a conveniance. Equivalent to * \code @@ -101,13 +90,13 @@ class TessellatedPath: } /*! - * Set the value of \ref m_max_segments. - * \param v value to which to assign to \ref m_max_segments + * Set the value of \ref m_max_recursion. + * \param v value to which to assign to \ref m_max_recursion */ TessellationParams& - max_segments(unsigned int v) + max_recursion(unsigned int v) { - m_max_segments = v; + m_max_recursion = v; return *this; } @@ -120,11 +109,10 @@ class TessellatedPath: float m_threshhold; /*! - * Maximum number of segments to tessellate each - * PathContour::interpolator_base from each - * PathContour of a Path. Default value is 32. + * Maximum number of times to cut a single edge in + * half. Default value is 5. */ - unsigned int m_max_segments; + unsigned int m_max_recursion; }; /*! diff --git a/src/fastuidraw/arc_tessellated_path.cpp b/src/fastuidraw/arc_tessellated_path.cpp index d5c45d987..da77f7bd4 100644 --- a/src/fastuidraw/arc_tessellated_path.cpp +++ b/src/fastuidraw/arc_tessellated_path.cpp @@ -130,8 +130,6 @@ ArcTessellatedPath(const Path &input, float tmp; SegmentStorage segment_storage; - d->m_params.m_max_segments = t_max(TP.m_max_segments, - contour->interpolator(e)->minimum_arc_tessellation_segments()); FASTUIDRAWassert(work_room.empty()); segment_storage.m_d = &work_room; @@ -213,8 +211,6 @@ ArcTessellatedPath(const Path &input, } FASTUIDRAWassert(total_needed == d->m_segment_data.size()); } - - d->m_params.m_max_segments = TP.m_max_segments; } fastuidraw::ArcTessellatedPath:: diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 32d8f31af..db4fa3840 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -59,9 +59,7 @@ namespace Tessellator(const TessellationParams &tess_params, const interpolator_generic *h): m_h(h), - m_thresh(tess_params), - m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), - m_max_size(tess_params.m_max_segments + 1) + m_thresh(tess_params) { } @@ -87,7 +85,6 @@ namespace const interpolator_generic *m_h; TessellationParams m_thresh; - unsigned int m_max_recursion, m_max_size; }; class ArcTessellator @@ -102,9 +99,7 @@ namespace ArcTessellator(const TessellationParams &tess_params, const interpolator_generic *h): m_h(h), - m_thresh(tess_params.m_threshhold), - m_max_recursion(fastuidraw::uint32_log2(tess_params.m_max_segments)), - m_max_size(tess_params.m_max_segments + 1) + m_thresh(tess_params) { } @@ -122,8 +117,7 @@ namespace float *out_threshhold) const; const interpolator_generic *m_h; - float m_thresh; - unsigned int m_max_recursion, m_max_size; + TessellationParams m_thresh; }; class InterpolatorBasePrivate @@ -371,7 +365,7 @@ tessellation_worker(unsigned int recurse_level, m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshhold); - if (recurse_level + 1u < m_max_recursion + if (recurse_level <= m_thresh.m_max_recursion && *out_threshhold > m_thresh.m_threshhold) { float tmpA(-1.0f), tmpB(-1.0f); @@ -426,14 +420,24 @@ tessellation_worker(unsigned int recurse_level, reference_counted_ptr L0, L1, R0, R1; vec2 midL, midR; static float tol(0.00001f); + float threshL, threshR; m_h->tessellate(inL, &L0, &L1, &midL, nullptr); m_h->tessellate(inR, &R0, &R1, &midR, nullptr); + if (recurse_level < m_h->minimum_arc_tessellation_recursion()) + { + tessellation_worker(recurse_level + 1u, out_data, L0, L1, + start, midL, mid, &threshL); + tessellation_worker(recurse_level + 1u, out_data, R0, R1, + mid, midR, end, &threshR); + *out_threshhold = t_max(threshL, threshR); + return; + } + /* compute the circle going through start, mid, end */ vec2 c, v0, v1, n0, n1, p0, p1; float s, det, r; - float threshL, threshR; p0 = 0.5f * (start + mid); p1 = 0.5f * (mid + end); @@ -447,7 +451,7 @@ tessellation_worker(unsigned int recurse_level, det = n1.y() * n0.x() - n0.y() * n1.x(); if (t_abs(det) < tol) { - if (recurse_level + 1u < m_max_recursion) + if (recurse_level < m_thresh.m_max_recursion) { tessellation_worker(recurse_level + 1u, out_data, L0, L1, start, midL, mid, &threshL); @@ -484,8 +488,8 @@ tessellation_worker(unsigned int recurse_level, threshR = t_abs(r - (c - midR).magnitude()); *out_threshhold = t_max(threshL, threshR); - if (recurse_level + 1u < m_max_recursion - && *out_threshhold > m_thresh) + if (recurse_level + 1u < m_thresh.m_max_recursion + && *out_threshhold > m_thresh.m_threshhold) { tessellation_worker(recurse_level + 1u, out_data, L0, L1, start, midL, mid, &threshL); @@ -767,12 +771,12 @@ deep_copy(const reference_counted_ptr &prev) const unsigned int fastuidraw::PathContour::bezier:: -minimum_arc_tessellation_segments(void) const +minimum_arc_tessellation_recursion(void) const { BezierPrivate *d; d = static_cast(m_d); - return 2 * d->m_pts.size(); + return uint32_log2(d->m_pts.size()); } ////////////////////////////////////// @@ -847,9 +851,9 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const unsigned int fastuidraw::PathContour::flat:: -minimum_arc_tessellation_segments(void) const +minimum_arc_tessellation_recursion(void) const { - return 1; + return 0; } ////////////////////////////////////// @@ -1016,9 +1020,9 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, unsigned int fastuidraw::PathContour::arc:: -minimum_arc_tessellation_segments(void) const +minimum_arc_tessellation_recursion(void) const { - return 1; + return 0; } void @@ -1416,7 +1420,7 @@ tessellation(const fastuidraw::Path &path, float thresh) ref = m_data.back(); params - .max_segments(ref->max_segments()) + .max_recursion(ref->tessellation_parameters().m_max_recursion) .threshhold(ref->effective_threshhold()); while(!m_done && ref->effective_threshhold() > thresh) @@ -1431,13 +1435,13 @@ tessellation(const fastuidraw::Path &path, float thresh) int no_improve_count; no_improve_count = 0; - params.m_max_segments *= 2; + ++params.m_max_recursion; last_tess = ref->effective_threshhold(); ref = FASTUIDRAWnew TessedPath(path, params); while (last_tess <= ref->effective_threshhold() && no_improve_count < max_tries) { - params.m_max_segments *= 2; + ++params.m_max_recursion; ref = FASTUIDRAWnew TessedPath(path, params); ++no_improve_count; } diff --git a/src/fastuidraw/private/path_util_private.cpp b/src/fastuidraw/private/path_util_private.cpp index 6dbe02024..52a7c68fa 100644 --- a/src/fastuidraw/private/path_util_private.cpp +++ b/src/fastuidraw/private/path_util_private.cpp @@ -25,18 +25,7 @@ fastuidraw::detail:: number_segments_for_tessellation(float radius, float arc_angle, const TessellatedPath::TessellationParams &P) { - float d, needed_sizef, theta; - unsigned int needed_size; - - d = t_max(1.0f - P.m_threshhold / radius, 0.5f); - theta = t_max(0.00001f, 0.5f * std::acos(d)); - needed_sizef = t_abs(arc_angle) / theta; - - /* we ask for one more than necessary, to ensure that we BEAT - * the tessellation requirement. - */ - needed_size = 1 + fastuidraw::t_max(3u, static_cast(needed_sizef)); - return fastuidraw::t_min(needed_size, P.m_max_segments); + return number_segments_for_tessellation(arc_angle, P.m_threshhold / radius); } unsigned int From 0a4d8e9065e4b79935ed2ac18e95da2c29a44ba6 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 18:05:28 +0300 Subject: [PATCH 48/52] fastuidraw/path: further interface tweaks Change-Id: If6cc8532d6a4d9ea4e928a3daab219dea1b51f29 --- inc/fastuidraw/path.hpp | 27 +++----- src/fastuidraw/path.cpp | 136 +++++++++++++++++++++++++--------------- 2 files changed, 94 insertions(+), 69 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 50b61df1b..2daf76188 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -136,15 +136,6 @@ class PathContour: ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const = 0; - /*! - * To be implemented by a derived class to return a reasonable - * lower bound on the needed number of times the edge should be - * cut in half in order to capture its shape. - */ - virtual - unsigned int - minimum_arc_tessellation_recursion(void) const = 0; - /*! * To be implemented by a derived class to return a fast (and approximate) * bounding box for the interpolator. @@ -209,10 +200,6 @@ class PathContour: virtual interpolator_base* deep_copy(const reference_counted_ptr &prev) const; - - virtual - unsigned int - minimum_arc_tessellation_recursion(void) const; }; /*! @@ -273,6 +260,15 @@ class PathContour: reference_counted_ptr *out_regionA, reference_counted_ptr *out_regionB, vec2 *out_p, float *out_threshholds) const = 0; + + /*! + * To be implemented by a derived class to return a reasonable + * lower bound on the needed number of times the edge should be + * cut in half in order to capture its shape. + */ + virtual + unsigned int + minimum_tessellation_recursion(void) const = 0; }; /*! @@ -334,7 +330,7 @@ class PathContour: virtual unsigned int - minimum_arc_tessellation_recursion(void) const; + minimum_tessellation_recursion(void) const; private: bezier(const bezier &q, @@ -398,9 +394,6 @@ class PathContour: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; - virtual - unsigned int - minimum_arc_tessellation_recursion(void) const; private: arc(const arc &q, const reference_counted_ptr &prev); diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index db4fa3840..745b62a18 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -59,16 +59,17 @@ namespace Tessellator(const TessellationParams &tess_params, const interpolator_generic *h): m_h(h), - m_thresh(tess_params) + m_thresh(tess_params), + m_minimum_tessellation_recursion(m_h->minimum_tessellation_recursion()) { } - void + unsigned int dump(TessellatedPath::PointStorage *out_data, float *out_threshhold) const; private: - void + unsigned int tessellation_worker(unsigned int recurse_level, TessellatedPath::PointStorage *out_data, fastuidraw::reference_counted_ptr in_src, @@ -85,6 +86,7 @@ namespace const interpolator_generic *m_h; TessellationParams m_thresh; + unsigned int m_minimum_tessellation_recursion; }; class ArcTessellator @@ -99,16 +101,17 @@ namespace ArcTessellator(const TessellationParams &tess_params, const interpolator_generic *h): m_h(h), - m_thresh(tess_params) + m_thresh(tess_params), + m_minimum_tessellation_recursion(m_h->minimum_tessellation_recursion()) { } - void + unsigned int dump(ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; private: - void + unsigned int tessellation_worker(unsigned int recurse_level, ArcTessellatedPath::SegmentStorage *out_data, fastuidraw::reference_counted_ptr in_L, @@ -116,8 +119,21 @@ namespace fastuidraw::vec2 start, fastuidraw::vec2 mid, fastuidraw::vec2 end, float *out_threshhold) const; + unsigned int + recurse(unsigned int recurse_level, + ArcTessellatedPath::SegmentStorage *out_data, + fastuidraw::reference_counted_ptr L0, + fastuidraw::reference_counted_ptr L1, + fastuidraw::reference_counted_ptr R0, + fastuidraw::reference_counted_ptr R1, + fastuidraw::vec2 start, fastuidraw::vec2 midL, + fastuidraw::vec2 mid, fastuidraw::vec2 midR, + fastuidraw::vec2 end, + float *out_threshhold) const; + const interpolator_generic *m_h; TessellationParams m_thresh; + unsigned int m_minimum_tessellation_recursion; }; class InterpolatorBasePrivate @@ -335,11 +351,13 @@ namespace ///////////////////////////////// // Tessellator methods -void +unsigned int Tessellator:: dump(TessellatedPath::PointStorage *out_data, float *out_threshhold) const { + unsigned int return_value; + *out_threshhold = -1.0f; /* * tessellate: note that we add the start point, then tessellate @@ -347,11 +365,13 @@ dump(TessellatedPath::PointStorage *out_data, * are added to m_data in order of time automatically. */ add_point(out_data, m_h->start_pt()); - tessellation_worker(0, out_data, nullptr, out_threshhold); + return_value = tessellation_worker(0, out_data, nullptr, out_threshhold); add_point(out_data, m_h->end_pt()); + + return return_value; } -void +unsigned int Tessellator:: tessellation_worker(unsigned int recurse_level, TessellatedPath::PointStorage *out_data, @@ -365,10 +385,12 @@ tessellation_worker(unsigned int recurse_level, m_h->tessellate(in_src, &rgnA, &rgnB, &p, out_threshhold); - if (recurse_level <= m_thresh.m_max_recursion - && *out_threshhold > m_thresh.m_threshhold) + if (recurse_level < m_minimum_tessellation_recursion + || (recurse_level <= m_thresh.m_max_recursion + && *out_threshhold > m_thresh.m_threshhold)) { float tmpA(-1.0f), tmpB(-1.0f); + unsigned int vA, vB; /* NOTE the order of recursing and adding to m_data: * - first we recurse into the left side @@ -379,21 +401,23 @@ tessellation_worker(unsigned int recurse_level, * mid point, and all points in the right side come * after the midpoint. */ - tessellation_worker(recurse_level + 1, out_data, rgnA, &tmpA); + vA = tessellation_worker(recurse_level + 1, out_data, rgnA, &tmpA); add_point(out_data, p); - tessellation_worker(recurse_level + 1, out_data, rgnB, &tmpB); + vB = tessellation_worker(recurse_level + 1, out_data, rgnB, &tmpB); *out_threshhold = t_max(tmpA, tmpB); + return t_max(vA, vB); } else { add_point(out_data, p); + return recurse_level; } } /////////////////////////////////////// // ArcTessellator methods -void +unsigned int ArcTessellator:: dump(ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const @@ -404,10 +428,34 @@ dump(ArcTessellatedPath::SegmentStorage *out_data, vec2 mid; m_h->tessellate(nullptr, &L, &R, &mid, nullptr); - tessellation_worker(1, out_data, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); + return tessellation_worker(1, out_data, L, R, m_h->start_pt(), mid, m_h->end_pt(), out_threshhold); } -void +unsigned int +ArcTessellator:: +recurse(unsigned int recurse_level, + ArcTessellatedPath::SegmentStorage *out_data, + fastuidraw::reference_counted_ptr L0, + fastuidraw::reference_counted_ptr L1, + fastuidraw::reference_counted_ptr R0, + fastuidraw::reference_counted_ptr R1, + fastuidraw::vec2 start, fastuidraw::vec2 midL, + fastuidraw::vec2 mid, fastuidraw::vec2 midR, + fastuidraw::vec2 end, + float *out_threshhold) const +{ + float threshL, threshR; + unsigned int vL, vR; + + vL = tessellation_worker(recurse_level + 1u, out_data, L0, L1, + start, midL, mid, &threshL); + vR = tessellation_worker(recurse_level + 1u, out_data, R0, R1, + mid, midR, end, &threshR); + *out_threshhold = fastuidraw::t_max(threshL, threshR); + return fastuidraw::t_max(vL, vR); +} + +unsigned int ArcTessellator:: tessellation_worker(unsigned int recurse_level, ArcTessellatedPath::SegmentStorage *out_data, @@ -425,14 +473,12 @@ tessellation_worker(unsigned int recurse_level, m_h->tessellate(inL, &L0, &L1, &midL, nullptr); m_h->tessellate(inR, &R0, &R1, &midR, nullptr); - if (recurse_level < m_h->minimum_arc_tessellation_recursion()) + if (recurse_level < m_minimum_tessellation_recursion) { - tessellation_worker(recurse_level + 1u, out_data, L0, L1, - start, midL, mid, &threshL); - tessellation_worker(recurse_level + 1u, out_data, R0, R1, - mid, midR, end, &threshR); - *out_threshhold = t_max(threshL, threshR); - return; + return recurse(recurse_level, out_data, + L0, L1, R0, R1, + start, midL, mid, midR, end, + out_threshhold); } /* compute the circle going through start, mid, end */ @@ -451,13 +497,12 @@ tessellation_worker(unsigned int recurse_level, det = n1.y() * n0.x() - n0.y() * n1.x(); if (t_abs(det) < tol) { - if (recurse_level < m_thresh.m_max_recursion) + if (recurse_level <= m_thresh.m_max_recursion) { - tessellation_worker(recurse_level + 1u, out_data, L0, L1, - start, midL, mid, &threshL); - tessellation_worker(recurse_level + 1u, out_data, R0, R1, - mid, midR, end, &threshR); - *out_threshhold = t_max(threshL, threshR); + return recurse(recurse_level, out_data, + L0, L1, R0, R1, + start, midL, mid, midR, end, + out_threshhold); } else { @@ -475,8 +520,8 @@ tessellation_worker(unsigned int recurse_level, *out_threshhold = t_max(*out_threshhold, detail::distance_to_line(mid, start, end)); + return recurse_level; } - return; } s = dot(v1, p1 - p0) / det; @@ -488,14 +533,13 @@ tessellation_worker(unsigned int recurse_level, threshR = t_abs(r - (c - midR).magnitude()); *out_threshhold = t_max(threshL, threshR); - if (recurse_level + 1u < m_thresh.m_max_recursion + if (recurse_level <= m_thresh.m_max_recursion && *out_threshhold > m_thresh.m_threshhold) { - tessellation_worker(recurse_level + 1u, out_data, L0, L1, - start, midL, mid, &threshL); - tessellation_worker(recurse_level + 1u, out_data, R0, R1, - mid, midR, end, &threshR); - *out_threshhold = t_max(threshL, threshR); + return recurse(recurse_level, out_data, + L0, L1, R0, R1, + start, midL, mid, midR, end, + out_threshhold); } else { @@ -508,6 +552,8 @@ tessellation_worker(unsigned int recurse_level, S.m_data.x() = std::atan2(start.y() - c.y(), start.x() - c.x()); S.m_data.y() = std::atan2(end.y() - c.y(), end.x() - c.x()); out_data->add_segment(S); + + return recurse_level; } } @@ -771,12 +817,12 @@ deep_copy(const reference_counted_ptr &prev) const unsigned int fastuidraw::PathContour::bezier:: -minimum_arc_tessellation_recursion(void) const +minimum_tessellation_recursion(void) const { BezierPrivate *d; d = static_cast(m_d); - return uint32_log2(d->m_pts.size()); + return 1 + uint32_log2(d->m_pts.size()); } ////////////////////////////////////// @@ -849,13 +895,6 @@ approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const out_max_bb->y() = fastuidraw::t_max(p0.y(), p1.y()); } -unsigned int -fastuidraw::PathContour::flat:: -minimum_arc_tessellation_recursion(void) const -{ - return 0; -} - ////////////////////////////////////// // fastuidraw::PathContour::arc methods fastuidraw::PathContour::arc:: @@ -1018,13 +1057,6 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, *out_threshhold = 0.0f; } -unsigned int -fastuidraw::PathContour::arc:: -minimum_arc_tessellation_recursion(void) const -{ - return 0; -} - void fastuidraw::PathContour::arc:: approximate_bounding_box(vec2 *out_min_bb, vec2 *out_max_bb) const From ebb66060ee991aa8b9f171b4a4a66361c587f58f Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 18:10:03 +0300 Subject: [PATCH 49/52] fastuidraw/path: return recursion depth in produce_tessellation() methods Change-Id: Ic08b6a7d14f0e05c6c6b1812e99833bc711f0c5c --- inc/fastuidraw/path.hpp | 26 ++++++++++++++++---------- src/fastuidraw/path.cpp | 20 ++++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/inc/fastuidraw/path.hpp b/inc/fastuidraw/path.hpp index 2daf76188..1fecd3f28 100644 --- a/inc/fastuidraw/path.hpp +++ b/inc/fastuidraw/path.hpp @@ -103,7 +103,9 @@ class PathContour: * from start_pt() to end_pt(). The routine must include BOTH start_pt() * and end_pt() in the result. Only the fields TessellatedPath::point::m_p, * and are to be filled; the other fields of TessellatedPath::point are - * filled by TessellatedPath. + * filled by TessellatedPath. In addition, returns the deepest number of + * times it recurses (for example each level is dividing the path in half). + * If the routine is not recursive, should return 0. * * \param tess_params tessellation parameters * \param out_data location to which to write the edge tessellated @@ -112,7 +114,7 @@ class PathContour: * approximation. */ virtual - void + unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, float *out_threshhold) const = 0; @@ -122,7 +124,11 @@ class PathContour: * from start_pt() to end_pt(). Only the fields ArcTessellatedPath::segment::m_p, * and ArcTessellatedPath::m_type, ArcTessellatedPath::m_data and * ArcTessellatedPath::m_radius are to be filled; the other fields of - * ArcTessellatedPath::segment are filled by ArcTessellatedPath. + * ArcTessellatedPath::segment are filled by ArcTessellatedPath. In addition, + * returns the deepest number of times it recurses (for example each level + * is dividing the path in half). If the routine is not recursive, should + * return 0. + * * * \param tess_params tessellation parameters * \param out_data location to which to write the tessellation @@ -131,7 +137,7 @@ class PathContour: * approximation. */ virtual - void + unsigned int produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const = 0; @@ -184,12 +190,12 @@ class PathContour: is_flat(void) const; virtual - void + unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual - void + unsigned int produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; @@ -231,12 +237,12 @@ class PathContour: {} virtual - void + unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual - void + unsigned int produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; @@ -385,12 +391,12 @@ class PathContour: deep_copy(const reference_counted_ptr &prev) const; virtual - void + unsigned int produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, float *out_threshholds) const; virtual - void + unsigned int produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const; diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 745b62a18..9aa909ba5 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -636,24 +636,24 @@ end_pt(void) const ////////////////////////////////////////////// // fastuidraw::PathContour::interpolator_generic methods -void +unsigned int fastuidraw::PathContour::interpolator_generic:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, float *out_threshhold) const { Tessellator tesser(tess_params, this); - tesser.dump(out_data, out_threshhold); + return tesser.dump(out_data, out_threshhold); } -void +unsigned int fastuidraw::PathContour::interpolator_generic:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, float *out_threshhold) const { ArcTessellator tesser(tess_params, this); - tesser.dump(out_data, out_threshhold); + return tesser.dump(out_data, out_threshhold); } //////////////////////////////////// @@ -834,7 +834,7 @@ is_flat(void) const return true; } -void +unsigned int fastuidraw::PathContour::flat:: produce_tessellation(const TessellatedPath::TessellationParams&, TessellatedPath::PointStorage *out_data, @@ -853,9 +853,10 @@ produce_tessellation(const TessellatedPath::TessellationParams&, out_data->add_point(p1); *out_threshhold = 0.0f; + return 0; } -void +unsigned int fastuidraw::PathContour::flat:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, @@ -872,6 +873,7 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, out_data->add_segment(S); *out_threshhold = 0.0f; + return 0; } fastuidraw::PathContour::interpolator_base* @@ -991,7 +993,7 @@ is_flat(void) const return false; } -void +unsigned int fastuidraw::PathContour::arc:: produce_tessellation(const TessellatedPath::TessellationParams &tess_params, TessellatedPath::PointStorage *out_data, @@ -1034,9 +1036,10 @@ produce_tessellation(const TessellatedPath::TessellationParams &tess_params, } *out_threshhold = d->m_radius * (1.0f - t_cos(delta_angle * 0.5f)); + return 0; } -void +unsigned int fastuidraw::PathContour::arc:: produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, ArcTessellatedPath::SegmentStorage *out_data, @@ -1055,6 +1058,7 @@ produce_tessellation(const ArcTessellatedPath::TessellationParams &tess_params, out_data->add_segment(S); *out_threshhold = 0.0f; + return 0; } void From cdd376f5ce8d620b212ad2140a257b12fe42e4c9 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 18:39:39 +0300 Subject: [PATCH 50/52] fastuidraw/path: return the recursion depth in tessellation and use that to increase refinement Change-Id: I8920b1b349bbc4c767b7fa29d9966fef46029ed6 --- inc/fastuidraw/arc_tessellated_path.hpp | 6 ++++++ inc/fastuidraw/tessellated_path.hpp | 6 ++++++ src/fastuidraw/arc_tessellated_path.cpp | 19 +++++++++++++++---- src/fastuidraw/tessellated_path.cpp | 19 +++++++++++++++---- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/inc/fastuidraw/arc_tessellated_path.hpp b/inc/fastuidraw/arc_tessellated_path.hpp index 0f746cb7f..fcdd84a7c 100644 --- a/inc/fastuidraw/arc_tessellated_path.hpp +++ b/inc/fastuidraw/arc_tessellated_path.hpp @@ -245,6 +245,12 @@ class ArcTessellatedPath: unsigned int max_segments(void) const; + /*! + * Returns the maximum recursion employed by any edge + */ + unsigned int + max_recursion(void) const; + /*! * Returns all the segment data */ diff --git a/inc/fastuidraw/tessellated_path.hpp b/inc/fastuidraw/tessellated_path.hpp index 3f0a99619..a94df22b4 100644 --- a/inc/fastuidraw/tessellated_path.hpp +++ b/inc/fastuidraw/tessellated_path.hpp @@ -215,6 +215,12 @@ class TessellatedPath: unsigned int max_segments(void) const; + /*! + * Returns the maximum recursion employed by any edge + */ + unsigned int + max_recursion(void) const; + /*! * Returns all the point data */ diff --git a/src/fastuidraw/arc_tessellated_path.cpp b/src/fastuidraw/arc_tessellated_path.cpp index da77f7bd4..578089370 100644 --- a/src/fastuidraw/arc_tessellated_path.cpp +++ b/src/fastuidraw/arc_tessellated_path.cpp @@ -39,7 +39,7 @@ namespace fastuidraw::BoundingBox m_bounding_box; fastuidraw::ArcTessellatedPath::TessellationParams m_params; float m_effective_threshhold; - unsigned int m_max_segments; + unsigned int m_max_segments, m_max_recursion; }; void @@ -87,7 +87,8 @@ ArcTessellatedPathPrivate(const fastuidraw::Path &input, m_edge_ranges(input.number_contours()), m_params(TP), m_effective_threshhold(0.0f), - m_max_segments(0u) + m_max_segments(0u), + m_max_recursion(0u) { } @@ -126,14 +127,15 @@ ArcTessellatedPath(const Path &input, d->m_edge_ranges[o].resize(contour->number_points()); for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) { - unsigned int needed; + unsigned int needed, recurse_depth; float tmp; SegmentStorage segment_storage; FASTUIDRAWassert(work_room.empty()); segment_storage.m_d = &work_room; - contour->interpolator(e)->produce_tessellation(d->m_params, &segment_storage, &tmp); + recurse_depth = contour->interpolator(e)->produce_tessellation(d->m_params, &segment_storage, &tmp); + d->m_max_recursion = t_max(d->m_max_recursion, recurse_depth); needed = work_room.size(); d->m_edge_ranges[o][e] = range_type(loc, loc + needed); @@ -250,6 +252,15 @@ max_segments(void) const return d->m_max_segments; } +unsigned int +fastuidraw::ArcTessellatedPath:: +max_recursion(void) const +{ + ArcTessellatedPathPrivate *d; + d = static_cast(m_d); + return d->m_max_recursion; +} + fastuidraw::c_array fastuidraw::ArcTessellatedPath:: segment_data(void) const diff --git a/src/fastuidraw/tessellated_path.cpp b/src/fastuidraw/tessellated_path.cpp index a5d7c0ff7..913aff009 100644 --- a/src/fastuidraw/tessellated_path.cpp +++ b/src/fastuidraw/tessellated_path.cpp @@ -39,7 +39,7 @@ namespace fastuidraw::BoundingBox m_bounding_box; fastuidraw::TessellatedPath::TessellationParams m_params; float m_effective_threshhold; - unsigned int m_max_segments; + unsigned int m_max_segments, m_max_recursion; fastuidraw::reference_counted_ptr m_stroked; fastuidraw::reference_counted_ptr m_filled; }; @@ -53,7 +53,8 @@ TessellatedPathPrivate(const fastuidraw::Path &input, m_edge_ranges(input.number_contours()), m_params(TP), m_effective_threshhold(0.0f), - m_max_segments(0u) + m_max_segments(0u), + m_max_recursion(0u) { } @@ -92,13 +93,14 @@ TessellatedPath(const Path &input, d->m_edge_ranges[o].resize(contour->number_points()); for(unsigned int e = 0, ende = contour->number_points(); e < ende; ++e) { - unsigned int needed; + unsigned int needed, recurse_depth; float tmp; PointStorage point_storage; FASTUIDRAWassert(work_room.empty()); point_storage.m_d = &work_room; - contour->interpolator(e)->produce_tessellation(d->m_params, &point_storage, &tmp); + recurse_depth = contour->interpolator(e)->produce_tessellation(d->m_params, &point_storage, &tmp); + d->m_max_recursion = t_max(d->m_max_recursion, recurse_depth); needed = work_room.size(); d->m_edge_ranges[o][e] = range_type(loc, loc + needed); @@ -240,6 +242,15 @@ max_segments(void) const return d->m_max_segments; } +unsigned int +fastuidraw::TessellatedPath:: +max_recursion(void) const +{ + TessellatedPathPrivate *d; + d = static_cast(m_d); + return d->m_max_recursion; +} + fastuidraw::c_array fastuidraw::TessellatedPath:: point_data(void) const From 2cee33c15d171b15c8c577f61e7542785d0ae5c0 Mon Sep 17 00:00:00 2001 From: Kevin Rogovin Date: Wed, 2 May 2018 18:57:07 +0300 Subject: [PATCH 51/52] fastuidraw/path: use max_recursion() method of TessellatedPath and ArcTessellatedPath + view segments in arc-tessellation as having 0 as error Change-Id: I1f1814a8af1757d5680930e7e7ced529267fbb42 --- src/fastuidraw/path.cpp | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/fastuidraw/path.cpp b/src/fastuidraw/path.cpp index 9aa909ba5..56cc53d07 100644 --- a/src/fastuidraw/path.cpp +++ b/src/fastuidraw/path.cpp @@ -515,11 +515,7 @@ tessellation_worker(unsigned int recurse_level, S.m_radius = 0.0f; out_data->add_segment(S); - *out_threshhold = t_max(detail::distance_to_line(p0, start, end), - detail::distance_to_line(p1, start, end)); - - *out_threshhold = t_max(*out_threshhold, - detail::distance_to_line(mid, start, end)); + *out_threshhold = 0.0f; return recurse_level; } } @@ -1409,8 +1405,7 @@ tessellation(const fastuidraw::Path &path, float thresh) TessParams params; vec2 bb_min, bb_max, bb_size; - /* always prefer to use distance threshholds over - * curvature; use the size of the bounding box times + /* use the size of the bounding box times * 1/500 as teh default tessellation factor. */ if (path.approximate_bounding_box(&bb_min, &bb_max)) @@ -1456,46 +1451,42 @@ tessellation(const fastuidraw::Path &path, float thresh) ref = m_data.back(); params - .max_recursion(ref->tessellation_parameters().m_max_recursion) + .max_recursion(ref->max_recursion()) .threshhold(ref->effective_threshhold()); while(!m_done && ref->effective_threshhold() > thresh) { - const int max_tries(6); - params.m_threshhold *= 0.5f; while(!m_done && ref->effective_threshhold() > params.m_threshhold) { float last_tess; - int no_improve_count; - no_improve_count = 0; ++params.m_max_recursion; last_tess = ref->effective_threshhold(); ref = FASTUIDRAWnew TessedPath(path, params); - while (last_tess <= ref->effective_threshhold() && no_improve_count < max_tries) - { - ++params.m_max_recursion; - ref = FASTUIDRAWnew TessedPath(path, params); - ++no_improve_count; - } - - if (no_improve_count < max_tries) + if (last_tess > ref->effective_threshhold()) { m_data.push_back(ref); + + /* + std::cout << "Add type = " << typeid(TessedPath).name() + << "(max_segs = " << ref->max_segments() << ", tess_factor = " + << ref->effective_threshhold() + << ")\n"; + */ } else { m_done = true; - /**/ - std::cout << "Tapped out on type = (max_segs = " - << ref->max_segments() << ", tess_factor = " + /* + std::cout << "Tapped out on type = " << typeid(TessedPath).name() + << "(max_segs = " << ref->max_segments() << ", tess_factor = " << ref->effective_threshhold() << ")\n"; - /**/ + */ } } } From c0b105aa79ebe1c98f2397b2cc0cf7555014c4ac Mon Sep 17 00:00:00 2001 From: Shixin Zeng Date: Wed, 2 May 2018 14:43:12 -0400 Subject: [PATCH 52/52] Rewrite create-resource-cpp in C++ Makes it more portable: no shell or perl required. --- make/Makefile.base.lib.mk | 3 + make/Makefile.settings.mk | 4 +- .../fastuidraw-create-resource-cpp-file.cpp | 56 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 shell_scripts/fastuidraw-create-resource-cpp-file.cpp diff --git a/make/Makefile.base.lib.mk b/make/Makefile.base.lib.mk index 5693058b3..01764786b 100644 --- a/make/Makefile.base.lib.mk +++ b/make/Makefile.base.lib.mk @@ -23,6 +23,9 @@ build/string_resources_cpp/%.resource_string.cpp: %.resource_string $(STRING_RES @mkdir -p $(dir $@) $(STRING_RESOURCE_CC) $< $(notdir $<) $(dir $@) +${STRING_RESOURCE_CC}: shell_scripts/fastuidraw-create-resource-cpp-file.cpp + $(CXX) $< -o $@ + FASTUIDRAW_STRING_RESOURCES_SRCS = $(patsubst %.resource_string, build/string_resources_cpp/%.resource_string.cpp, $(FASTUIDRAW_RESOURCE_STRING) ) CLEAN_FILES += $(FASTUIDRAW_STRING_RESOURCES_SRCS) diff --git a/make/Makefile.settings.mk b/make/Makefile.settings.mk index db8ac8ddc..889a5b0d2 100644 --- a/make/Makefile.settings.mk +++ b/make/Makefile.settings.mk @@ -2,6 +2,7 @@ MINGW_BUILD = 0 UNAME = $(shell uname -s) UNAMER= $(shell uname -r) +EXE_SUFFIX = ifeq ($(findstring MINGW,$(UNAME)),MINGW) MINGW_BUILD = 1 ifeq ($(findstring 1.0, $(UNAMER)), 1.0) @@ -11,6 +12,7 @@ ifeq ($(findstring MINGW,$(UNAME)),MINGW) else ifeq ($(findstring MINGW32,$(UNAME)),MINGW32) MINGW_MODE = MINGW32 endif + EXE_SUFFIX = .exe endif #TODO: detection for DARWIN @@ -20,7 +22,7 @@ DARWIN_BUILD = 0 # Setting for building libFastUIDraw.so base library CXX ?= g++ CC ?= gcc -STRING_RESOURCE_CC = shell_scripts/fastuidraw-create-resource-cpp-file.sh +STRING_RESOURCE_CC = shell_scripts/fastuidraw-create-resource-cpp-file${EXE_SUFFIX} ####################################### # Platform specific libraries needed diff --git a/shell_scripts/fastuidraw-create-resource-cpp-file.cpp b/shell_scripts/fastuidraw-create-resource-cpp-file.cpp new file mode 100644 index 000000000..4bfbf59be --- /dev/null +++ b/shell_scripts/fastuidraw-create-resource-cpp-file.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +using namespace std; + +void show_usage(const char* app) +{ + cerr << "Usage: " << app << " input_file output_name output_directory" << endl + << "Creates a .cpp file named output_name.cpp in the directory output_directory" << endl + << "which when added to a project adds a resource for fastuidraw::fetch_static_resource()" << endl + << "named output_name with value the contents of input_file. " << endl; +} + +int main(int argc, char **argv) +{ + if (argc < 4) { + show_usage(argv[0]); + return EXIT_FAILURE; + } + + string in_filename(argv[1]); + string out_filename(argv[2]); + string out_dirname(argv[3]); + + ifstream inf(in_filename); + if (inf.fail()) { + cerr << "Input file " << in_filename << " not found" << endl; + return EXIT_FAILURE; + } + + string out_path = out_dirname + '/' + out_filename + ".cpp"; + ofstream outf(out_path, ios::binary | ios::out); + if (outf.fail()) { + cerr << "Can't open output file at:" << out_path << endl; + return EXIT_FAILURE; + } + + outf << "#include \n" << endl + << "namespace { \n\tconst uint8_t values[]={ " << endl; + + string line; + while (getline(inf, line).good()) { + for (int c : line) { + outf << c << ","; + } + outf << 10 << ","; // End-of-Line + } + + outf << " 0 };" << endl + <<" fastuidraw::static_resource R(\"" << out_filename << "\", fastuidraw::c_array(values, sizeof(values)));" << endl + <<"\n}" << endl; + + + return EXIT_SUCCESS; +}