kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Interpolators for line segment, and faster transforms
rodzic
41eb2b503e
commit
841c141ebf
|
@ -6,4 +6,4 @@ add_library(pico_vector
|
||||||
|
|
||||||
target_include_directories(pico_vector INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(pico_vector INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
target_link_libraries(pico_vector pico_stdlib)
|
target_link_libraries(pico_vector pico_stdlib hardware_interp)
|
|
@ -10,44 +10,42 @@ namespace pimoroni {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoVector::rotate(std::vector<pretty_poly::contour_t<picovector_point_type>> &contours, Point origin, float angle) {
|
void PicoVector::rotate(std::vector<pretty_poly::contour_t<picovector_point_type>> &contours, Point origin, float angle) {
|
||||||
pretty_poly::mat3_t t2 = pretty_poly::mat3_t::translation(origin.x, origin.y);
|
pretty_poly::point_t<picovector_point_type> t{(picovector_point_type)origin.x, (picovector_point_type)origin.y};
|
||||||
pretty_poly::mat3_t t1 = pretty_poly::mat3_t::translation(-origin.x, -origin.y);
|
angle = (2 * (float)M_PI / 360.f) * angle;
|
||||||
angle = 2 * M_PI * (angle / 360.0f);
|
pretty_poly::mat2_t r = pretty_poly::mat2_t::rotation(angle);
|
||||||
pretty_poly::mat3_t r = pretty_poly::mat3_t::rotation(angle);
|
|
||||||
for(auto &contour : contours) {
|
for(auto &contour : contours) {
|
||||||
for(auto i = 0u; i < contour.count; i++) {
|
for(auto i = 0u; i < contour.count; i++) {
|
||||||
contour.points[i] *= t1;
|
contour.points[i] -= t;
|
||||||
contour.points[i] *= r;
|
contour.points[i] *= r;
|
||||||
contour.points[i] *= t2;
|
contour.points[i] += t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoVector::translate(std::vector<pretty_poly::contour_t<picovector_point_type>> &contours, Point translation) {
|
void PicoVector::translate(std::vector<pretty_poly::contour_t<picovector_point_type>> &contours, Point translation) {
|
||||||
pretty_poly::mat3_t t = pretty_poly::mat3_t::translation(translation.x, translation.y);
|
pretty_poly::point_t<picovector_point_type> t{(picovector_point_type)translation.x, (picovector_point_type)translation.y};
|
||||||
for(auto &contour : contours) {
|
for(auto &contour : contours) {
|
||||||
for(auto i = 0u; i < contour.count; i++) {
|
for(auto i = 0u; i < contour.count; i++) {
|
||||||
contour.points[i] *= t;
|
contour.points[i] += t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoVector::rotate(pretty_poly::contour_t<picovector_point_type> &contour, Point origin, float angle) {
|
void PicoVector::rotate(pretty_poly::contour_t<picovector_point_type> &contour, Point origin, float angle) {
|
||||||
pretty_poly::mat3_t t2 = pretty_poly::mat3_t::translation(origin.x, origin.y);
|
pretty_poly::point_t<picovector_point_type> t{(picovector_point_type)origin.x, (picovector_point_type)origin.y};
|
||||||
pretty_poly::mat3_t t1 = pretty_poly::mat3_t::translation(-origin.x, -origin.y);
|
angle = (2 * (float)M_PI / 360.f) * angle;
|
||||||
angle = 2 * M_PI * (angle / 360.0f);
|
pretty_poly::mat2_t r = pretty_poly::mat2_t::rotation(angle);
|
||||||
pretty_poly::mat3_t r = pretty_poly::mat3_t::rotation(angle);
|
|
||||||
for(auto i = 0u; i < contour.count; i++) {
|
for(auto i = 0u; i < contour.count; i++) {
|
||||||
contour.points[i] *= t1;
|
contour.points[i] -= t;
|
||||||
contour.points[i] *= r;
|
contour.points[i] *= r;
|
||||||
contour.points[i] *= t2;
|
contour.points[i] += t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoVector::translate(pretty_poly::contour_t<picovector_point_type> &contour, Point translation) {
|
void PicoVector::translate(pretty_poly::contour_t<picovector_point_type> &contour, Point translation) {
|
||||||
pretty_poly::mat3_t t = pretty_poly::mat3_t::translation(translation.x, translation.y);
|
pretty_poly::point_t<picovector_point_type> t{(picovector_point_type)translation.x, (picovector_point_type)translation.y};
|
||||||
for(auto i = 0u; i < contour.count; i++) {
|
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<float> caret(0, 0);
|
pretty_poly::point_t<float> caret(0, 0);
|
||||||
|
|
||||||
// Prepare a transformation matrix for character and offset rotation
|
// 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);
|
pretty_poly::mat3_t transform = pretty_poly::mat3_t::rotation(angle);
|
||||||
|
|
||||||
// Align text from the bottom left
|
// Align text from the bottom left
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "pretty_poly.hpp"
|
#include "pretty_poly.hpp"
|
||||||
|
|
||||||
|
#include "hardware/interp.h"
|
||||||
|
|
||||||
#ifdef PP_DEBUG
|
#ifdef PP_DEBUG
|
||||||
#define debug(...) printf(__VA_ARGS__)
|
#define debug(...) printf(__VA_ARGS__)
|
||||||
|
@ -79,8 +80,8 @@ namespace pretty_poly {
|
||||||
std::swap(sx, ex);
|
std::swap(sx, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Early out if line is completely outside the tile
|
// Early out if line is completely outside the tile, or has no lines
|
||||||
if (ey < 0 || sy >= (int)node_buffer_size) return;
|
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);
|
debug(" + line segment from %d, %d to %d, %d\n", sx, sy, ex, ey);
|
||||||
|
|
||||||
|
@ -123,13 +124,16 @@ namespace pretty_poly {
|
||||||
x += xinc * xjump;
|
x += xinc * xjump;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interp1->base[1] = full_tile_width;
|
||||||
|
interp1->accum[0] = x;
|
||||||
|
|
||||||
// loop over scanlines
|
// loop over scanlines
|
||||||
while(count--) {
|
while(count--) {
|
||||||
// consume accumulated error
|
// 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
|
// 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);
|
debug(" + adding node at %d, %d\n", x, y);
|
||||||
// add node to node list
|
// add node to node list
|
||||||
nodes[y][node_counts[y]++] = nx;
|
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(" - 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);
|
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);
|
//memset(nodes, 0, node_buffer_size * sizeof(unsigned) * 32);
|
||||||
|
|
||||||
|
@ -303,18 +315,21 @@ namespace pretty_poly {
|
||||||
// render the tile
|
// render the tile
|
||||||
rect_t bounds;
|
rect_t bounds;
|
||||||
render_nodes(tile, bounds);
|
render_nodes(tile, bounds);
|
||||||
|
if (bounds.empty()) {
|
||||||
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()) {
|
|
||||||
continue;
|
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);
|
settings::callback(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interp_restore(interp1, &interp1_save);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace pretty_poly {
|
||||||
|
|
||||||
// 3x3 matrix for coordinate transformations
|
// 3x3 matrix for coordinate transformations
|
||||||
struct mat3_t {
|
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() = default;
|
||||||
mat3_t(const mat3_t &m) = default;
|
mat3_t(const mat3_t &m) = default;
|
||||||
inline mat3_t& operator*= (const mat3_t &m) {
|
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;}
|
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
|
// point type for contour points
|
||||||
template<typename T = int>
|
template<typename T = int>
|
||||||
struct __attribute__ ((packed)) point_t {
|
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 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 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 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 float a) {x /= a; y /= a; return *this;}
|
||||||
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;}
|
||||||
|
@ -60,6 +84,11 @@ namespace pretty_poly {
|
||||||
this->x = (m.v00 * tx + m.v01 * ty + m.v02);
|
this->x = (m.v00 * tx + m.v01 * ty + m.v02);
|
||||||
this->y = (m.v10 * tx + m.v11 * ty + m.v12);
|
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;
|
int x, y, w, h;
|
||||||
rect_t() : x(0), y(0), w(0), h(0) {}
|
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) {}
|
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) {
|
rect_t intersection(const rect_t &c) {
|
||||||
return rect_t(std::max(this->x, c.x), std::max(this->y, c.y),
|
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)),
|
std::max(0, std::min(this->x + this->w, c.x + c.w) - std::max(this->x, c.x)),
|
||||||
|
|
|
@ -18,4 +18,6 @@ target_compile_definitions(usermod_picovector INTERFACE
|
||||||
MODULE_PICOVECTOR_ENABLED=1
|
MODULE_PICOVECTOR_ENABLED=1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(usermod_picovector INTERFACE hardware_interp)
|
||||||
|
|
||||||
target_link_libraries(usermod INTERFACE usermod_picovector)
|
target_link_libraries(usermod INTERFACE usermod_picovector)
|
||||||
|
|
Ładowanie…
Reference in New Issue