diff --git a/libraries/pico_vector/pico_vector.cmake b/libraries/pico_vector/pico_vector.cmake index cecbff4f..92a168d2 100644 --- a/libraries/pico_vector/pico_vector.cmake +++ b/libraries/pico_vector/pico_vector.cmake @@ -6,4 +6,4 @@ add_library(pico_vector target_include_directories(pico_vector INTERFACE ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(pico_vector pico_stdlib) \ No newline at end of file +target_link_libraries(pico_vector pico_stdlib hardware_interp) \ No newline at end of file diff --git a/libraries/pico_vector/pico_vector.cpp b/libraries/pico_vector/pico_vector.cpp index 0e13d60d..d748ad60 100644 --- a/libraries/pico_vector/pico_vector.cpp +++ b/libraries/pico_vector/pico_vector.cpp @@ -10,44 +10,42 @@ namespace pimoroni { } void PicoVector::rotate(std::vector> &contours, Point origin, float angle) { - pretty_poly::mat3_t t2 = pretty_poly::mat3_t::translation(origin.x, origin.y); - pretty_poly::mat3_t t1 = pretty_poly::mat3_t::translation(-origin.x, -origin.y); - angle = 2 * M_PI * (angle / 360.0f); - pretty_poly::mat3_t r = pretty_poly::mat3_t::rotation(angle); + pretty_poly::point_t t{(picovector_point_type)origin.x, (picovector_point_type)origin.y}; + angle = (2 * (float)M_PI / 360.f) * angle; + pretty_poly::mat2_t r = pretty_poly::mat2_t::rotation(angle); for(auto &contour : contours) { for(auto i = 0u; i < contour.count; i++) { - contour.points[i] *= t1; + contour.points[i] -= t; contour.points[i] *= r; - contour.points[i] *= t2; + contour.points[i] += t; } } } void PicoVector::translate(std::vector> &contours, Point translation) { - pretty_poly::mat3_t t = pretty_poly::mat3_t::translation(translation.x, translation.y); + pretty_poly::point_t t{(picovector_point_type)translation.x, (picovector_point_type)translation.y}; for(auto &contour : contours) { for(auto i = 0u; i < contour.count; i++) { - contour.points[i] *= t; + contour.points[i] += t; } } } void PicoVector::rotate(pretty_poly::contour_t &contour, Point origin, float angle) { - pretty_poly::mat3_t t2 = pretty_poly::mat3_t::translation(origin.x, origin.y); - pretty_poly::mat3_t t1 = pretty_poly::mat3_t::translation(-origin.x, -origin.y); - angle = 2 * M_PI * (angle / 360.0f); - pretty_poly::mat3_t r = pretty_poly::mat3_t::rotation(angle); + pretty_poly::point_t t{(picovector_point_type)origin.x, (picovector_point_type)origin.y}; + angle = (2 * (float)M_PI / 360.f) * angle; + pretty_poly::mat2_t r = pretty_poly::mat2_t::rotation(angle); for(auto i = 0u; i < contour.count; i++) { - contour.points[i] *= t1; + contour.points[i] -= t; contour.points[i] *= r; - contour.points[i] *= t2; + contour.points[i] += t; } } void PicoVector::translate(pretty_poly::contour_t &contour, Point translation) { - pretty_poly::mat3_t t = pretty_poly::mat3_t::translation(translation.x, translation.y); + pretty_poly::point_t t{(picovector_point_type)translation.x, (picovector_point_type)translation.y}; for(auto i = 0u; i < contour.count; i++) { - contour.points[i] *= t; + contour.points[i] += t; } } @@ -115,7 +113,7 @@ namespace pimoroni { pretty_poly::point_t caret(0, 0); // Prepare a transformation matrix for character and offset rotation - angle = 2 * M_PI * (angle / 360.0f); + angle = (2 * (float)M_PI / 360.f) * angle; pretty_poly::mat3_t transform = pretty_poly::mat3_t::rotation(angle); // Align text from the bottom left diff --git a/libraries/pico_vector/pretty_poly.cpp b/libraries/pico_vector/pretty_poly.cpp index be1d5527..5d13a48e 100644 --- a/libraries/pico_vector/pretty_poly.cpp +++ b/libraries/pico_vector/pretty_poly.cpp @@ -8,6 +8,7 @@ #include "pretty_poly.hpp" +#include "hardware/interp.h" #ifdef PP_DEBUG #define debug(...) printf(__VA_ARGS__) @@ -79,8 +80,8 @@ namespace pretty_poly { std::swap(sx, ex); } - // Early out if line is completely outside the tile - if (ey < 0 || sy >= (int)node_buffer_size) return; + // Early out if line is completely outside the tile, or has no lines + if (ey < 0 || sy >= (int)node_buffer_size || sy == ey) return; debug(" + line segment from %d, %d to %d, %d\n", sx, sy, ex, ey); @@ -123,13 +124,16 @@ namespace pretty_poly { x += xinc * xjump; } + interp1->base[1] = full_tile_width; + interp1->accum[0] = x; + // loop over scanlines while(count--) { // consume accumulated error - while(e > dy) {e -= dy; x += xinc;} + while(e > dy) {e -= dy; interp1->add_raw[0] = xinc;} // clamp node x value to tile bounds - int nx = std::max(std::min(x, full_tile_width), 0); + const int nx = interp1->peek[0]; debug(" + adding node at %d, %d\n", x, y); // add node to node list nodes[y][node_counts[y]++] = nx; @@ -270,6 +274,14 @@ namespace pretty_poly { debug(" - bounds %d, %d (%d x %d)\n", polygon_bounds.x, polygon_bounds.y, polygon_bounds.w, polygon_bounds.h); debug(" - clip %d, %d (%d x %d)\n", settings::clip.x, settings::clip.y, settings::clip.w, settings::clip.h); + interp_hw_save_t interp1_save; + interp_save(interp1, &interp1_save); + + interp_config cfg = interp_default_config(); + interp_config_set_clamp(&cfg, true); + interp_config_set_signed(&cfg, true); + interp_set_config(interp1, 0, &cfg); + interp1->base[0] = 0; //memset(nodes, 0, node_buffer_size * sizeof(unsigned) * 32); @@ -303,18 +315,21 @@ namespace pretty_poly { // render the tile rect_t bounds; render_nodes(tile, bounds); - - tile.data += bounds.x + tile.stride * bounds.y; - bounds.x += tile.bounds.x; - bounds.y += tile.bounds.y; - tile.bounds = bounds.intersection(tile.bounds); - if (tile.bounds.empty()) { + if (bounds.empty()) { continue; } + tile.data += bounds.x + tile.stride * bounds.y; + tile.bounds.x += bounds.x; + tile.bounds.y += bounds.y; + tile.bounds.w = bounds.w; + tile.bounds.h = bounds.h; + settings::callback(tile); } } + + interp_restore(interp1, &interp1_save); } } diff --git a/libraries/pico_vector/pretty_poly_types.hpp b/libraries/pico_vector/pretty_poly_types.hpp index 51076f8a..5677bbc3 100644 --- a/libraries/pico_vector/pretty_poly_types.hpp +++ b/libraries/pico_vector/pretty_poly_types.hpp @@ -14,7 +14,7 @@ namespace pretty_poly { // 3x3 matrix for coordinate transformations struct mat3_t { - float v00, v10, v20, v01, v11, v21, v02, v12, v22 = 0.0f; + float v00 = 0.0f, v10 = 0.0f, v20 = 0.0f, v01 = 0.0f, v11 = 0.0f, v21 = 0.0f, v02 = 0.0f, v12 = 0.0f, v22 = 0.0f; mat3_t() = default; mat3_t(const mat3_t &m) = default; inline mat3_t& operator*= (const mat3_t &m) { @@ -43,6 +43,29 @@ namespace pretty_poly { mat3_t r = mat3_t::identity(); r.v00 = x; r.v11 = y; return r;} }; + // 2x2 matrix for rotations and scales + struct mat2_t { + float v00 = 0.0f, v10 = 0.0f, v01 = 0.0f, v11 = 0.0f; + mat2_t() = default; + mat2_t(const mat2_t &m) = default; + inline mat2_t& operator*= (const mat2_t &m) { + float r00 = this->v00 * m.v00 + this->v01 * m.v10; + float r01 = this->v00 * m.v01 + this->v01 * m.v11; + float r10 = this->v10 * m.v00 + this->v11 * m.v10; + float r11 = this->v10 * m.v01 + this->v11 * m.v11; + this->v00 = r00; this->v01 = r01; + this->v10 = r10; this->v11 = r11; + return *this; + } + + static mat2_t identity() {mat2_t m; m.v00 = m.v11 = 1.0f; return m;} + static mat2_t rotation(float a) { + float c = cosf(a), s = sinf(a); mat2_t r; + r.v00 = c; r.v01 = -s; r.v10 = s; r.v11 = c; return r;} + static mat2_t scale(float x, float y) { + mat2_t r; r.v00 = x; r.v11 = y; return r;} + }; + // point type for contour points template struct __attribute__ ((packed)) point_t { @@ -52,6 +75,7 @@ namespace pretty_poly { inline point_t& operator-= (const point_t &a) {x -= a.x; y -= a.y; return *this;} inline point_t& operator+= (const point_t &a) {x += a.x; y += a.y; return *this;} inline point_t& operator*= (const float a) {x *= a; y *= a; return *this;} + inline point_t& operator*= (const mat2_t &a) {this->transform(a); return *this;} inline point_t& operator*= (const mat3_t &a) {this->transform(a); return *this;} inline point_t& operator/= (const float a) {x /= a; y /= a; return *this;} inline point_t& operator/= (const point_t &a) {x /= a.x; y /= a.y; return *this;} @@ -60,6 +84,11 @@ namespace pretty_poly { this->x = (m.v00 * tx + m.v01 * ty + m.v02); this->y = (m.v10 * tx + m.v11 * ty + m.v12); } + void transform(const mat2_t &m) { + float tx = x, ty = y; + this->x = (m.v00 * tx + m.v01 * ty); + this->y = (m.v10 * tx + m.v11 * ty); + } }; @@ -78,7 +107,7 @@ namespace pretty_poly { int x, y, w, h; rect_t() : x(0), y(0), w(0), h(0) {} rect_t(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {} - bool empty() const {return this->w == 0 && this->h == 0;} + bool empty() const {return this->w == 0 || this->h == 0;} rect_t intersection(const rect_t &c) { return rect_t(std::max(this->x, c.x), std::max(this->y, c.y), std::max(0, std::min(this->x + this->w, c.x + c.w) - std::max(this->x, c.x)), diff --git a/micropython/modules/picovector/micropython.cmake b/micropython/modules/picovector/micropython.cmake index 69624f20..c513cdcc 100644 --- a/micropython/modules/picovector/micropython.cmake +++ b/micropython/modules/picovector/micropython.cmake @@ -18,4 +18,6 @@ target_compile_definitions(usermod_picovector INTERFACE MODULE_PICOVECTOR_ENABLED=1 ) +target_link_libraries(usermod_picovector INTERFACE hardware_interp) + target_link_libraries(usermod INTERFACE usermod_picovector)