kopia lustrzana https://github.com/pimoroni/pimoroni-pico
PicoVector: Use tile renderer for all pens.
rodzic
d39516f9e1
commit
dd7d6262df
|
@ -143,6 +143,12 @@ namespace pimoroni {
|
|||
|
||||
typedef int Pen;
|
||||
|
||||
struct Tile {
|
||||
int32_t x, y, w, h;
|
||||
uint32_t stride;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
struct Rect;
|
||||
|
||||
struct Point {
|
||||
|
@ -307,7 +313,7 @@ namespace pimoroni {
|
|||
virtual void frame_convert(PenType type, conversion_callback_func callback);
|
||||
virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent);
|
||||
|
||||
virtual bool render_pico_vector_tile(const Rect &bounds, uint8_t* alpha_data, uint32_t stride, uint8_t alpha_type) { return false; }
|
||||
virtual bool render_tile(const Tile *tile) { return false; }
|
||||
|
||||
void set_font(const bitmap::font_t *font);
|
||||
void set_font(const hershey::font_t *font);
|
||||
|
@ -454,6 +460,8 @@ namespace pimoroni {
|
|||
static size_t buffer_size(uint w, uint h) {
|
||||
return w * h / 2;
|
||||
}
|
||||
|
||||
bool render_tile(const Tile *tile);
|
||||
};
|
||||
|
||||
class PicoGraphics_PenP8 : public PicoGraphics {
|
||||
|
@ -487,6 +495,8 @@ namespace pimoroni {
|
|||
static size_t buffer_size(uint w, uint h) {
|
||||
return w * h;
|
||||
}
|
||||
|
||||
bool render_tile(const Tile *tile);
|
||||
};
|
||||
|
||||
class PicoGraphics_PenRGB332 : public PicoGraphics {
|
||||
|
@ -511,6 +521,8 @@ namespace pimoroni {
|
|||
static size_t buffer_size(uint w, uint h) {
|
||||
return w * h;
|
||||
}
|
||||
|
||||
bool render_tile(const Tile *tile);
|
||||
};
|
||||
|
||||
class PicoGraphics_PenRGB565 : public PicoGraphics {
|
||||
|
@ -535,6 +547,8 @@ namespace pimoroni {
|
|||
void set_pixel_alpha(const Point &p, const uint8_t a) override;
|
||||
|
||||
bool supports_alpha_blend() override {return true;}
|
||||
|
||||
bool render_tile(const Tile *tile);
|
||||
};
|
||||
|
||||
class PicoGraphics_PenRGB888 : public PicoGraphics {
|
||||
|
@ -551,6 +565,8 @@ namespace pimoroni {
|
|||
static size_t buffer_size(uint w, uint h) {
|
||||
return w * h * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
bool render_tile(const Tile *tile);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -185,4 +185,27 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool PicoGraphics_PenP4::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint8_t *pdest = &((uint8_t *)frame_buffer)[(tile->x / 2) + ((tile->y + y) * (bounds.w / 2))];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint8_t shift = (x & 1) ? 0 : 4;
|
||||
uint8_t alpha = *palpha;
|
||||
|
||||
if(alpha == 0) {
|
||||
} else {
|
||||
*pdest &= shift ? 0x0f : 0xf0;
|
||||
*pdest |= color << shift;
|
||||
}
|
||||
|
||||
if(x & 1) {
|
||||
pdest++;
|
||||
}
|
||||
palpha++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,4 +171,24 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PicoGraphics_PenP8::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint8_t *pdest = &((uint8_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *palpha;
|
||||
|
||||
if(alpha == 0) {
|
||||
} else {
|
||||
*pdest = color;
|
||||
}
|
||||
|
||||
pdest++;
|
||||
palpha++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,4 +145,24 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool PicoGraphics_PenRGB332::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint8_t *pdest = &((uint8_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *palpha;
|
||||
|
||||
// TODO: Try to alpha blend RGB332... somewhat?
|
||||
if(alpha == 0) {
|
||||
} else {
|
||||
*pdest = color;
|
||||
}
|
||||
|
||||
pdest++;
|
||||
palpha++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,4 +93,41 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PicoGraphics_PenRGB565::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint16_t *pdest = &((uint16_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint16_t dest = *pdest;
|
||||
uint8_t alpha = *palpha;
|
||||
|
||||
if(alpha == 255) {
|
||||
*pdest = color;
|
||||
}else if(alpha == 0) {
|
||||
}else{
|
||||
// blend tha pixel
|
||||
uint16_t sr = (color & 0b1111100000000000) >> 11;
|
||||
uint16_t sg = (color & 0b0000011111100000) >> 5;
|
||||
uint16_t sb = (color & 0b0000000000011111);
|
||||
|
||||
uint16_t dr = (dest & 0b1111100000000000) >> 11;
|
||||
uint16_t dg = (dest & 0b0000011111100000) >> 5;
|
||||
uint16_t db = (dest & 0b0000000000011111);
|
||||
|
||||
uint8_t r = ((sr * alpha) + (dr * (255 - alpha))) >> 8;
|
||||
uint8_t g = ((sg * alpha) + (dg * (255 - alpha))) >> 8;
|
||||
uint8_t b = ((sb * alpha) + (db * (255 - alpha))) >> 8;
|
||||
|
||||
// recombine the channels
|
||||
*pdest = (r << 11) | (g << 5) | (b);
|
||||
}
|
||||
|
||||
pdest++;
|
||||
palpha++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,4 +36,24 @@ namespace pimoroni {
|
|||
*buf++ = color;
|
||||
}
|
||||
}
|
||||
bool PicoGraphics_PenRGB888::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint32_t *pdest = &((uint32_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *palpha;
|
||||
|
||||
// TODO: Alpha blending
|
||||
if(alpha == 0) {
|
||||
} else {
|
||||
*pdest = color;
|
||||
}
|
||||
|
||||
pdest++;
|
||||
palpha++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -6,9 +6,6 @@
|
|||
namespace pimoroni {
|
||||
PicoGraphics *PicoVector::graphics = nullptr;
|
||||
|
||||
uint8_t PicoVector::max_alpha = 4;
|
||||
const uint8_t *PicoVector::alpha_map = alpha_map_x4;
|
||||
|
||||
void PicoVector::draw(pp_poly_t *poly) {
|
||||
pp_transform(NULL);
|
||||
pp_render(poly);
|
||||
|
|
|
@ -31,10 +31,6 @@ namespace pimoroni {
|
|||
private:
|
||||
static PicoGraphics *graphics;
|
||||
af_text_metrics_t text_metrics;
|
||||
static constexpr uint8_t alpha_map_x4[4] {0, 128, 192, 255};
|
||||
static constexpr uint8_t alpha_map_x16[16] {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 255};
|
||||
static uint8_t max_alpha;
|
||||
static const uint8_t *alpha_map;
|
||||
|
||||
public:
|
||||
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
|
||||
|
@ -57,50 +53,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
static void tile_callback(const pp_tile_t *tile) {
|
||||
uint8_t *tile_data = tile->data;
|
||||
|
||||
if(PicoVector::graphics->supports_alpha_blend() && _pp_antialias != PP_AA_NONE) {
|
||||
if (PicoVector::graphics->render_pico_vector_tile({tile->x, tile->y, tile->w, tile->h},
|
||||
tile->data,
|
||||
tile->stride,
|
||||
(uint8_t)_pp_antialias)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto y = 0; y < tile->h; y++) {
|
||||
for(auto x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *tile_data++;
|
||||
if (alpha >= max_alpha) {
|
||||
PicoVector::graphics->pixel({x + tile->x, y + tile->y});
|
||||
} else if (alpha > 0) {
|
||||
alpha = alpha_map[alpha];
|
||||
PicoVector::graphics->set_pixel_alpha({x + tile->x, y + tile->y}, alpha);
|
||||
}
|
||||
}
|
||||
tile_data += tile->stride - tile->w;
|
||||
}
|
||||
} else {
|
||||
for(auto y = 0; y < tile->h; y++) {
|
||||
for(auto x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *tile_data++;
|
||||
if (alpha) {
|
||||
PicoVector::graphics->pixel({x + tile->x, y + tile->y});
|
||||
}
|
||||
}
|
||||
tile_data += tile->stride - tile->w;
|
||||
}
|
||||
}
|
||||
// TODO: we're using a cast here to avoid a hard dependency link between
|
||||
// PicoGraphics and PicoVector. These types might subtly mismatch, though...
|
||||
PicoVector::graphics->render_tile((pimoroni::Tile *)tile);
|
||||
}
|
||||
|
||||
void set_antialiasing(pp_antialias_t antialias) {
|
||||
pp_antialias(antialias);
|
||||
if(antialias == PP_AA_X16) {
|
||||
alpha_map = alpha_map_x16;
|
||||
max_alpha = 16;
|
||||
} else {
|
||||
alpha_map = alpha_map_x4;
|
||||
max_alpha = 4;
|
||||
}
|
||||
}
|
||||
|
||||
void set_font_size(unsigned int font_size) {
|
||||
|
|
|
@ -31,30 +31,25 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef PP_MALLOC
|
||||
#define PP_MALLOC(size) malloc(size)
|
||||
#define PP_REALLOC(p, size) realloc(p, size)
|
||||
#define PP_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#ifndef PP_COORD_TYPE
|
||||
#define PP_COORD_TYPE float
|
||||
#endif
|
||||
|
||||
#ifndef PP_NODE_BUFFER_HEIGHT
|
||||
#define PP_NODE_BUFFER_HEIGHT 16
|
||||
#endif
|
||||
|
||||
#ifndef PP_MAX_NODES_PER_SCANLINE
|
||||
#define PP_MAX_NODES_PER_SCANLINE 16
|
||||
#endif
|
||||
|
||||
#ifndef PP_TILE_BUFFER_SIZE
|
||||
#define PP_TILE_BUFFER_SIZE 4096
|
||||
#define PP_TILE_BUFFER_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef PP_SCALE_TO_ALPHA
|
||||
#define PP_SCALE_TO_ALPHA 1
|
||||
#endif
|
||||
|
||||
#if defined(PICO_ON_DEVICE) && PICO_ON_DEVICE
|
||||
|
@ -62,12 +57,6 @@
|
|||
#include "hardware/interp.h"
|
||||
#endif
|
||||
|
||||
#ifdef PP_DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -103,7 +92,7 @@ pp_rect_t pp_rect_merge(pp_rect_t *r1, pp_rect_t *r2);
|
|||
pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m);
|
||||
|
||||
// antialias levels
|
||||
typedef enum {PP_AA_NONE = 0, PP_AA_X4 = 1, PP_AA_X16 = 2} pp_antialias_t;
|
||||
typedef enum {PP_AA_NONE = 0, PP_AA_FAST = 1, PP_AA_X4 = 1, PP_AA_BEST = 2, PP_AA_X16 = 2} pp_antialias_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t x, y, w, h;
|
||||
|
@ -144,7 +133,19 @@ pp_rect_t pp_polygon_bounds(pp_poly_t *p);
|
|||
|
||||
#ifdef PP_IMPLEMENTATION
|
||||
|
||||
pp_rect_t _pp_clip = (pp_rect_t){0, 0, 320, 240};
|
||||
#ifndef PP_MALLOC
|
||||
#define PP_MALLOC(size) malloc(size)
|
||||
#define PP_REALLOC(p, size) realloc(p, size)
|
||||
#define PP_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#ifdef PP_DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...)
|
||||
#endif
|
||||
|
||||
pp_rect_t _pp_clip = (pp_rect_t){-INT_MAX, -INT_MAX, INT_MAX, INT_MAX};
|
||||
pp_tile_callback_t _pp_tile_callback = NULL;
|
||||
pp_antialias_t _pp_antialias = PP_AA_X4;
|
||||
pp_mat3_t *_pp_transform = NULL;
|
||||
|
@ -245,7 +246,7 @@ pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m) {
|
|||
|
||||
// pp_tile_t implementation
|
||||
uint8_t pp_tile_get(const pp_tile_t *tile, const int32_t x, const int32_t y) {
|
||||
return tile->data[(x - tile->x) + (y - tile->y) * tile->stride] * (255 >> _pp_antialias >> _pp_antialias);
|
||||
return tile->data[(x - tile->x) + (y - tile->y) * PP_TILE_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
// pp_contour_t implementation
|
||||
|
@ -273,14 +274,16 @@ pp_rect_t pp_polygon_bounds(pp_poly_t *p) {
|
|||
|
||||
// buffer that each tile is rendered into before callback
|
||||
// allocate one extra byte to allow a small optimization in the row renderer
|
||||
const uint32_t tile_buffer_size = PP_TILE_BUFFER_SIZE;
|
||||
uint8_t tile_buffer[PP_TILE_BUFFER_SIZE + 1];
|
||||
uint8_t tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
|
||||
|
||||
// polygon node buffer handles at most 16 line intersections per scanline
|
||||
// is this enough for cjk/emoji? (requires a 2kB buffer)
|
||||
int32_t nodes[PP_NODE_BUFFER_HEIGHT][PP_MAX_NODES_PER_SCANLINE * 2];
|
||||
uint32_t node_counts[PP_NODE_BUFFER_HEIGHT];
|
||||
int32_t nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
|
||||
uint32_t node_counts[PP_TILE_BUFFER_SIZE * 4];
|
||||
|
||||
uint8_t _pp_alpha_map_none[2] = {0, 255};
|
||||
uint8_t _pp_alpha_map_x4[5] = {0, 63, 127, 190, 255};
|
||||
uint8_t _pp_alpha_map_x16[17] = {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};
|
||||
|
||||
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
_pp_clip = (pp_rect_t){.x = x, .y = y, .w = w, .h = h};
|
||||
|
@ -291,12 +294,8 @@ void pp_tile_callback(pp_tile_callback_t callback) {
|
|||
}
|
||||
|
||||
// maximum tile bounds determined by antialias level
|
||||
uint32_t _pp_tile_width, _pp_tile_height;
|
||||
void pp_antialias(pp_antialias_t antialias) {
|
||||
_pp_antialias = antialias;
|
||||
// recalculate the tile size for rendering based on antialiasing level
|
||||
_pp_tile_height = PP_NODE_BUFFER_HEIGHT >> _pp_antialias;
|
||||
_pp_tile_width = (int)(tile_buffer_size / _pp_tile_height);
|
||||
}
|
||||
|
||||
pp_mat3_t *pp_transform(pp_mat3_t *transform) {
|
||||
|
@ -329,34 +328,15 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
|
|||
int32_t tx = sx; sx = ex; ex = tx;
|
||||
}
|
||||
|
||||
// Early out if line is completely outside the tile, or has no lines
|
||||
if (ey < 0 || sy >= (int)PP_NODE_BUFFER_HEIGHT || sy == ey) return;
|
||||
// early out if line is completely outside the tile, or has no gradient
|
||||
if (ey < 0 || sy >= (int)(PP_TILE_BUFFER_SIZE << _pp_antialias) || sy == ey) return;
|
||||
|
||||
debug(" + line segment from %d, %d to %d, %d\n", sx, sy, ex, ey);
|
||||
|
||||
// Determine how many in-bounds lines to render
|
||||
// determine how many in-bounds lines to render
|
||||
int y = _pp_max(0, sy);
|
||||
int count = _pp_min((int)PP_NODE_BUFFER_HEIGHT, ey) - y;
|
||||
int count = _pp_min((int)(PP_TILE_BUFFER_SIZE << _pp_antialias), ey) - y;
|
||||
|
||||
// Handle cases where x is completely off to one side or other
|
||||
if (_pp_max(sx, ex) <= 0) {
|
||||
while (count--) {
|
||||
nodes[y][node_counts[y]++] = 0;
|
||||
++y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int full_tile_width = (_pp_tile_width << _pp_antialias);
|
||||
if (_pp_min(sx, ex) >= full_tile_width) {
|
||||
while (count--) {
|
||||
nodes[y][node_counts[y]++] = full_tile_width;
|
||||
++y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal case
|
||||
int x = sx;
|
||||
int e = 0;
|
||||
|
||||
|
@ -364,7 +344,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
|
|||
const int einc = abs(ex - sx) + 1;
|
||||
const int dy = ey - sy;
|
||||
|
||||
// If sy < 0 jump to the start, note this does use a divide
|
||||
// if sy < 0 jump to the start, note this does use a divide
|
||||
// but potentially saves many wasted loops below, so is likely worth it.
|
||||
if (sy < 0) {
|
||||
e = einc * -sy;
|
||||
|
@ -373,34 +353,34 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
|
|||
x += xinc * xjump;
|
||||
}
|
||||
|
||||
#ifdef USE_RP2040_INTERP
|
||||
interp1->base[1] = full_tile_width;
|
||||
interp1->accum[0] = x;
|
||||
// #ifdef USE_RP2040_INTERP
|
||||
// interp1->base[1] = full_tile_width;
|
||||
// interp1->accum[0] = x;
|
||||
|
||||
// loop over scanlines
|
||||
while(count--) {
|
||||
// consume accumulated error
|
||||
while(e > dy) {e -= dy; interp1->add_raw[0] = xinc;}
|
||||
// // loop over scanlines
|
||||
// while(count--) {
|
||||
// // consume accumulated error
|
||||
// while(e > dy) {e -= dy; interp1->add_raw[0] = xinc;}
|
||||
|
||||
// clamp node x value to tile bounds
|
||||
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;
|
||||
// // clamp node x value to tile bounds
|
||||
// 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;
|
||||
|
||||
// step to next scanline and accumulate error
|
||||
y++;
|
||||
e += einc;
|
||||
}
|
||||
#else
|
||||
// // step to next scanline and accumulate error
|
||||
// y++;
|
||||
// e += einc;
|
||||
// }
|
||||
// #else
|
||||
// loop over scanlines
|
||||
while(count--) {
|
||||
// consume accumulated error
|
||||
while(e > dy) {e -= dy; x += xinc;}
|
||||
|
||||
// clamp node x value to tile bounds
|
||||
int nx = _pp_max(_pp_min(x, full_tile_width), 0);
|
||||
debug(" + adding node at %d, %d\n", x, y);
|
||||
int nx = _pp_max(_pp_min(x, (PP_TILE_BUFFER_SIZE << _pp_antialias)), 0);
|
||||
//debug(" + adding node at %d, %d\n", x, y);
|
||||
// add node to node list
|
||||
nodes[y][node_counts[y]++] = nx;
|
||||
|
||||
|
@ -408,7 +388,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
|
|||
y++;
|
||||
e += einc;
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
void build_nodes(pp_path_t *contour, pp_rect_t *bounds) {
|
||||
|
@ -419,34 +399,17 @@ void build_nodes(pp_path_t *contour, pp_rect_t *bounds) {
|
|||
.y = bounds->y * aa_scale
|
||||
};
|
||||
|
||||
// start with the last point to close the loop
|
||||
pp_point_t last = {
|
||||
.x = (contour->points[contour->count - 1].x),
|
||||
.y = (contour->points[contour->count - 1].y)
|
||||
};
|
||||
|
||||
if(_pp_transform) {
|
||||
last = pp_point_transform(&last, _pp_transform);
|
||||
}
|
||||
|
||||
last.x *= aa_scale;
|
||||
last.y *= aa_scale;
|
||||
|
||||
// start with the last point to close the loop, transform it, scale for antialiasing, and offset to tile origin
|
||||
pp_point_t last = contour->points[contour->count - 1];
|
||||
if(_pp_transform) last = pp_point_transform(&last, _pp_transform);
|
||||
last.x *= aa_scale; last.y *= aa_scale;
|
||||
last = pp_point_sub(&last, &tile_origin);
|
||||
|
||||
for(uint32_t i = 0; i < contour->count; i++) {
|
||||
pp_point_t point = {
|
||||
.x = (contour->points[i].x),
|
||||
.y = (contour->points[i].y)
|
||||
};
|
||||
|
||||
if(_pp_transform) {
|
||||
point = pp_point_transform(&point, _pp_transform);
|
||||
}
|
||||
|
||||
point.x *= aa_scale;
|
||||
point.y *= aa_scale;
|
||||
|
||||
// fetch next point, transform it, scale for antialiasing, and offset to tile origin
|
||||
pp_point_t point = contour->points[i];
|
||||
if(_pp_transform) point = pp_point_transform(&point, _pp_transform);
|
||||
point.x *= aa_scale; point.y *= aa_scale;
|
||||
point = pp_point_sub(&point, &tile_origin);
|
||||
|
||||
add_line_segment_to_nodes(last, point);
|
||||
|
@ -459,81 +422,75 @@ int compare_nodes(const void* a, const void* b) {
|
|||
return *((int*)a) - *((int*)b);
|
||||
}
|
||||
|
||||
pp_rect_t render_nodes(uint8_t *buffer, pp_rect_t *tb) {
|
||||
int maxy = -1;
|
||||
pp_rect_t render_nodes(pp_rect_t *tb) {
|
||||
pp_rect_t rb = {PP_TILE_BUFFER_SIZE << _pp_antialias, PP_TILE_BUFFER_SIZE << _pp_antialias, 0, 0}; // render bounds
|
||||
int maxx = 0, minx = PP_TILE_BUFFER_SIZE << _pp_antialias;
|
||||
debug(" + render tile %d, %d - %d, %d\n", tb->x, tb->y, tb->w, tb->h);
|
||||
|
||||
pp_rect_t rb; // render bounds
|
||||
rb.y = 0;
|
||||
rb.x = tb->w;
|
||||
int maxx = 0;
|
||||
PP_COORD_TYPE aa_scale = (PP_COORD_TYPE)(1 << _pp_antialias);
|
||||
int anitialias_mask = (1 << _pp_antialias) - 1;
|
||||
for(int y = 0; y < ((int)PP_TILE_BUFFER_SIZE << _pp_antialias); y++) {
|
||||
|
||||
for(int32_t y = 0; y < PP_NODE_BUFFER_HEIGHT; y++) {
|
||||
if(node_counts[y] == 0) {
|
||||
if (y == rb.y) ++rb.y;
|
||||
continue;
|
||||
}
|
||||
// debug(" : row %d node count %d\n", y, node_counts[y]);
|
||||
|
||||
if(node_counts[y] == 0) continue; // no nodes on this raster line
|
||||
|
||||
qsort(&nodes[y][0], node_counts[y], sizeof(int), compare_nodes);
|
||||
|
||||
unsigned char* row_data = &buffer[(y >> _pp_antialias) * _pp_tile_width];
|
||||
bool rendered_any = false;
|
||||
unsigned char* row_data = &tile_buffer[(y >> _pp_antialias) * PP_TILE_BUFFER_SIZE];
|
||||
|
||||
for(uint32_t i = 0; i < node_counts[y]; i += 2) {
|
||||
int sx = nodes[y][i + 0];
|
||||
int ex = nodes[y][i + 1];
|
||||
|
||||
if(sx == ex) {
|
||||
if(sx == ex) { // empty span, nothing to do
|
||||
continue;
|
||||
}
|
||||
|
||||
rendered_any = true;
|
||||
// update render bounds
|
||||
rb.x = _pp_min(rb.x, sx);
|
||||
rb.y = _pp_min(rb.y, y);
|
||||
minx = _pp_min(_pp_min(sx, ex), minx);
|
||||
maxx = _pp_max(_pp_max(sx, ex), maxx);
|
||||
rb.h = y - rb.y + 1;
|
||||
|
||||
maxx = _pp_max((ex - 1) >> _pp_antialias, maxx);
|
||||
//debug(" - render span at %d from %d to %d\n", y, sx, ex);
|
||||
|
||||
debug(" - render span at %d from %d to %d\n", y, sx, ex);
|
||||
|
||||
if (_pp_antialias) {
|
||||
int ax = sx / aa_scale;
|
||||
const int aex = ex / aa_scale;
|
||||
|
||||
rb.x = _pp_min(ax, rb.x);
|
||||
|
||||
if (ax == aex) {
|
||||
row_data[ax] += ex - sx;
|
||||
continue;
|
||||
}
|
||||
|
||||
row_data[ax] += aa_scale - (sx & anitialias_mask);
|
||||
for(ax++; ax < aex; ax++) {
|
||||
row_data[ax] += aa_scale;
|
||||
}
|
||||
|
||||
// This might add 0 to the byte after the end of the row, we pad the tile data
|
||||
// by 1 byte to ensure that is OK
|
||||
row_data[ax] += ex & anitialias_mask;
|
||||
} else {
|
||||
rb.x = _pp_min(sx, rb.x);
|
||||
for(int x = sx; x < ex; x++) {
|
||||
row_data[x]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rendered_any) {
|
||||
debug(" - rendered line %d\n", y);
|
||||
maxy = y;
|
||||
}
|
||||
else if (y == rb.y) {
|
||||
debug(" - render nothing on line %d\n", y);
|
||||
++rb.y;
|
||||
// rasterise the span into the tile buffer
|
||||
do {
|
||||
row_data[sx >> _pp_antialias]++;
|
||||
} while(++sx < ex);
|
||||
}
|
||||
}
|
||||
|
||||
rb.w = maxx - minx;
|
||||
|
||||
// shifting the width and height effectively "floors" the result which can
|
||||
// mean we lose a pixel off the right or bottom edge of the tile. by adding
|
||||
// either 1 (at x4) or 3 (at x16) we change that to a "ceil" instead ensuring
|
||||
// the full tile bounds are returned
|
||||
if(_pp_antialias) {
|
||||
rb.w += (_pp_antialias | 0b1);
|
||||
rb.h += (_pp_antialias | 0b1);
|
||||
}
|
||||
|
||||
rb.x >>= _pp_antialias;
|
||||
rb.y >>= _pp_antialias;
|
||||
maxy >>= _pp_antialias;
|
||||
rb.w = (maxx >= rb.x) ? maxx + 1 - rb.x : 0;
|
||||
rb.h = (maxy >= rb.y) ? maxy + 1 - rb.y : 0;
|
||||
rb.w >>= _pp_antialias;
|
||||
rb.h >>= _pp_antialias;
|
||||
|
||||
uint8_t *p_alpha_map = _pp_alpha_map_none;
|
||||
if(_pp_antialias == 1) p_alpha_map = _pp_alpha_map_x4;
|
||||
if(_pp_antialias == 2) p_alpha_map = _pp_alpha_map_x16;
|
||||
#if PP_SCALE_TO_ALPHA == 1
|
||||
for(int y = rb.y; y < rb.y + rb.h; y++) {
|
||||
unsigned char* row_data = &tile_buffer[y * PP_TILE_BUFFER_SIZE + rb.x];
|
||||
for(int x = rb.x; x < rb.x + rb.w; x++) {
|
||||
*row_data = p_alpha_map[*row_data];
|
||||
row_data++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
debug(" : rendered tile bounds %d, %d (%d x %d)\n", rb.x, rb.y, rb.w, rb.h);
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
@ -553,7 +510,7 @@ void pp_render(pp_poly_t *polygon) {
|
|||
polygon_bounds = pp_rect_transform(&polygon_bounds, _pp_transform);
|
||||
}
|
||||
|
||||
debug(" - bounds %d, %d (%d x %d)\n", polygon_bounds.x, polygon_bounds.y, polygon_bounds.w, polygon_bounds.h);
|
||||
debug(" - polygon 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", _pp_clip.x, _pp_clip.y, _pp_clip.w, _pp_clip.h);
|
||||
|
||||
#ifdef USE_RP2040_INTERP
|
||||
|
@ -569,9 +526,9 @@ void pp_render(pp_poly_t *polygon) {
|
|||
|
||||
// iterate over tiles
|
||||
debug(" - processing tiles\n");
|
||||
for(int32_t y = polygon_bounds.y; y < polygon_bounds.y + polygon_bounds.h; y += _pp_tile_height) {
|
||||
for(int32_t x = polygon_bounds.x; x < polygon_bounds.x + polygon_bounds.w; x += _pp_tile_width) {
|
||||
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = _pp_tile_width, .h = _pp_tile_height};
|
||||
for(int32_t y = polygon_bounds.y; y < polygon_bounds.y + polygon_bounds.h; y += PP_TILE_BUFFER_SIZE) {
|
||||
for(int32_t x = polygon_bounds.x; x < polygon_bounds.x + polygon_bounds.w; x += PP_TILE_BUFFER_SIZE) {
|
||||
pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = PP_TILE_BUFFER_SIZE, .h = PP_TILE_BUFFER_SIZE};
|
||||
tb = pp_rect_intersection(&tb, &_pp_clip);
|
||||
debug(" : %d, %d (%d x %d)\n", tb.x, tb.y, tb.w, tb.h);
|
||||
|
||||
|
@ -580,7 +537,7 @@ void pp_render(pp_poly_t *polygon) {
|
|||
|
||||
// clear existing tile data and nodes
|
||||
memset(node_counts, 0, sizeof(node_counts));
|
||||
memset(tile_buffer, 0, tile_buffer_size);
|
||||
memset(tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE);
|
||||
|
||||
// build the nodes for each pp_path_t
|
||||
for(uint32_t i = 0; i < polygon->count; i++) {
|
||||
|
@ -592,17 +549,15 @@ void pp_render(pp_poly_t *polygon) {
|
|||
debug(" : render the tile\n");
|
||||
// render the tile
|
||||
|
||||
pp_rect_t rb = render_nodes(tile_buffer, &tb);
|
||||
pp_rect_t rb = render_nodes(&tb);
|
||||
tb.x += rb.x; tb.y += rb.y; tb.w = rb.w; tb.h = rb.h;
|
||||
|
||||
debug(" - adjusted render tile bounds %d, %d (%d x %d)\n", rb.x, rb.y, rb.w, rb.h);
|
||||
|
||||
if(pp_rect_empty(&tb)) { debug(" : empty after rendering, skipping\n"); continue; }
|
||||
|
||||
pp_tile_t tile = {
|
||||
.x = tb.x, .y = tb.y, .w = tb.w, .h = tb.h,
|
||||
.stride = (uint32_t)_pp_tile_width,
|
||||
.data = tile_buffer + rb.x + _pp_tile_width * rb.y
|
||||
.stride = PP_TILE_BUFFER_SIZE,
|
||||
.data = tile_buffer + rb.x + (PP_TILE_BUFFER_SIZE * rb.y)
|
||||
};
|
||||
|
||||
_pp_tile_callback(&tile);
|
||||
|
|
|
@ -114,6 +114,8 @@ static const mp_map_elem_t VECTOR_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_NONE), MP_ROM_INT(0) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_X4), MP_ROM_INT(1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_X16), MP_ROM_INT(2) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_FAST), MP_ROM_INT(1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_BEST), MP_ROM_INT(2) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_VECTOR_globals, VECTOR_globals_table);
|
||||
|
|
Ładowanie…
Reference in New Issue