Skip to content

Commit

Permalink
fixed node buffer height bug
Browse files Browse the repository at this point in the history
  • Loading branch information
lowfatcode committed Sep 24, 2023
1 parent 7419d36 commit 2cbe061
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"string_view": "cpp",
"unordered_map": "cpp",
"__locale": "c",
"optional": "c"
"optional": "c",
"pretty-poly.h": "c"
}
}
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,23 +206,25 @@ void tile_render_callback(const pp_tile_t *tile) {

Note that on RP2040 interp1 is used by pretty poly. If your callback uses interp1 it must save and restore the state.

### `tile_t`
### `pp_tile_t`

Information needed to blend a rendered tile into your framebuffer.

```c++
struct tile_t {
rect_t bounds; // bounds of tile in framebuffer coordinates
unsigned stride; // width of row in bytes
uint8_t *data; // pointer to mask data

tile_t() {};
int get_value(int x, int y);
int32_t x, y, w, h; // bounds of tile in framebuffer coordinates
uint32_t stride; // row stride of tile data
uint8_t *data; // pointer to start of mask data
};
```
This object is passed into your callback function for each tile providing the area of the framebuffer to write to with the mask data needed for blending.
`uint8_t pp_tile_get_value(pp_tile_t *tile, int32_t x, int32_t y)`
`
Returns the value in the tile at `x`, `y `
### `rect_t`
Defines a rectangle with a top left corner, width, and height.
Expand Down
10 changes: 5 additions & 5 deletions examples/character.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ void set_pen(colour c) {
pen = c;
}

void tile_render_callback(const pp_tile_t *t) {
for(int32_t y = 0; y < t->h; y++) {
for(int32_t x = 0; x < t->w; x++) {
void tile_render_callback(const pp_tile_t *tile) {
for(int32_t y = 0; y < tile->h; y++) {
for(int32_t x = 0; x < tile->w; x++) {
colour alpha_pen = pen;
alpha_pen.rgba.a = alpha(pen.rgba.a, pp_tile_get_value(t, x, y));
buffer[y + t->y][x + t->x] = blend(buffer[y + t->y][x + t->x], alpha_pen);
alpha_pen.rgba.a = alpha(pen.rgba.a, pp_tile_get_value(tile, x, y));
buffer[y + tile->y][x + tile->x] = blend(buffer[y + tile->y][x + tile->x], alpha_pen);
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions examples/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include <stdint.h>
#include <sys/time.h>

typedef union {
struct __attribute__((__packed__)) {
Expand Down Expand Up @@ -65,4 +66,10 @@ colour create_colour_hsv(float h, float s, float v, float a) {
case 4: return create_colour(t, p, bv, a * 255);
case 5: return create_colour(bv, p, q, a * 255);
}
}

uint64_t time_ms() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (((uint64_t)tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
}
15 changes: 12 additions & 3 deletions examples/logo.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "ctype.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

#include "pretty-poly.h"

#include "helpers.h"

const int WIDTH = 1024;
Expand All @@ -14,11 +17,11 @@ void set_pen(colour c) {
}

void tile_render_callback(const pp_tile_t *t) {
for(int32_t y = 0; y < t->h; y++) {
for(int32_t x = 0; x < t->w; x++) {
for(int32_t y = t->y; y < t->y + t->h; y++) {
for(int32_t x = t->x; x < t->x + t->w; x++) {
colour alpha_pen = pen;
alpha_pen.rgba.a = alpha(pen.rgba.a, pp_tile_get_value(t, x, y));
buffer[y + t->y][x + t->x] = blend(buffer[y + t->y][x + t->x], alpha_pen);
buffer[y][x] = blend(buffer[y][x], alpha_pen);
}
}
}
Expand Down Expand Up @@ -289,6 +292,8 @@ int main() {
char logo_svg_path[] = "M3260 3933 c-168 -179 -274 -287 -503 -520 -248 -253 -248 -253 -1442 -253 -657 0 -1195 -3 -1195 -6 0 -9 124 -189 132 -192 5 -2 8 -9 8 -15 0 -6 9 -20 19 -31 11 -12 27 -35 38 -53 10 -18 31 -50 47 -73 29 -41 29 -41 -59 -173 -49 -73 -93 -133 -97 -135 -4 -2 -8 -9 -8 -14 0 -6 -17 -34 -38 -62 -21 -28 -42 -57 -46 -64 -6 -10 154 -12 805 -12 446 0 814 -1 816 -4 2 -2 -9 -23 -25 -47 -34 -51 -104 -188 -122 -239 -7 -19 -16 -44 -20 -55 -53 -128 -67 -261 -69 -641 -1 -117 -4 -164 -13 -171 -7 -6 -31 -13 -53 -16 -22 -3 -47 -8 -56 -12 -19 -7 -32 20 -50 110 -7 33 -13 61 -15 63 -6 8 -85 -51 -115 -86 -83 -97 -98 -161 -80 -347 20 -205 30 -241 83 -294 45 -46 99 -67 205 -80 126 -15 263 -65 396 -145 35 -20 113 -100 158 -161 24 -33 49 -66 56 -72 6 -7 13 -18 15 -24 3 -9 10 -9 27 0 12 7 20 19 17 26 -2 7 1 16 9 18 7 3 28 36 46 74 30 63 32 76 32 168 0 55 -4 111 -10 125 -6 14 -10 27 -9 30 0 3 -12 27 -28 54 -28 48 -28 48 11 90 82 86 150 228 169 351 6 43 17 61 78 130 39 44 73 82 76 85 43 43 192 269 185 280 -3 6 -2 10 4 10 27 0 190 372 210 480 5 30 13 87 17 125 4 39 8 75 9 80 1 6 3 30 3 55 2 45 2 45 734 43 403 -2 729 0 723 5 -5 4 -14 15 -20 24 -5 9 -65 98 -132 197 -68 99 -123 186 -123 192 0 7 6 20 14 28 8 9 69 97 135 196 122 180 122 180 -494 183 -564 2 -640 5 -606 26 4 3 11 23 15 44 3 21 13 61 21 88 8 27 31 108 51 179 20 72 45 162 55 200 11 39 28 102 39 140 10 39 23 87 30 108 6 21 10 43 8 48 -2 6 -32 -20 -68 -58z m-2188 -993 c-3 -149 1 -152 43 -24 14 43 35 98 46 122 20 43 35 50 87 36 19 -6 22 -11 17 -35 -4 -15 -15 -46 -26 -68 -10 -22 -19 -46 -19 -54 0 -7 -4 -17 -9 -23 -5 -5 -16 -29 -24 -54 -15 -45 -15 -45 18 -82 40 -43 51 -98 41 -195 -12 -112 -50 -143 -177 -143 -43 0 -81 5 -84 10 -8 13 -14 476 -7 578 5 73 5 73 51 70 46 -3 46 -3 43 -138z m476 107 c2 -10 1 -29 -2 -43 -6 -22 -11 -24 -70 -24 -63 0 -64 0 -70 -31 -3 -17 -6 -62 -6 -100 0 -69 0 -69 56 -69 55 0 55 0 52 -42 -3 -43 -3 -43 -55 -46 -53 -3 -53 -3 -53 -93 0 -89 0 -89 70 -89 70 0 70 0 70 -39 0 -48 -4 -50 -127 -50 -69 0 -94 4 -104 15 -9 11 -10 51 -5 162 4 81 7 187 6 236 -2 135 9 234 27 238 8 2 59 1 112 -2 83 -4 96 -8 99 -23z m820 21 c8 -8 12 -53 12 -132 1 -104 12 -189 33 -246 4 -8 8 -28 11 -45 15 -90 19 -111 26 -120 5 -5 10 -30 12 -55 3 -44 3 -45 -30 -48 -44 -4 -59 10 -67 61 -3 23 -10 60 -15 82 -5 22 -12 62 -15 89 -8 59 -21 50 -34 -24 -14 -80 -39 -189 -46 -200 -8 -14 -58 -13 -72 1 -12 12 -9 56 7 94 4 11 15 52 25 90 9 39 26 106 37 150 13 48 23 122 25 185 2 58 6 111 8 118 6 15 67 16 83 0z m869 -32 c43 -46 47 -85 36 -334 -8 -192 -11 -211 -31 -240 -43 -59 -157 -65 -212 -11 -37 37 -43 100 -36 357 6 182 7 195 28 222 30 36 71 50 133 45 41 -4 56 -10 82 -39z m485 -86 c3 -75 15 -159 28 -210 12 -47 26 -105 31 -130 5 -25 14 -65 20 -90 20 -85 18 -95 -19 -98 -41 -4 -62 12 -62 48 0 15 -6 45 -13 66 -7 22 -13 44 -13 49 0 6 -4 39 -9 75 -8 65 -8 65 -25 -5 -10 -38 -23 -101 -31 -140 -7 -38 -19 -76 -25 -82 -16 -17 -59 -17 -72 0 -11 13 -8 31 48 242 23 85 34 156 40 245 10 156 12 162 59 158 36 -3 36 -3 43 -128z m-2979 78 c3 -24 4 -82 3 -129 -3 -87 -3 -87 43 -92 106 -13 134 -53 135 -195 0 -93 -16 -142 -54 -162 -28 -15 -193 -30 -205 -19 -6 6 -11 132 -13 324 -4 315 -4 315 41 315 45 0 45 0 50 -42z m1007 -238 c0 -280 0 -280 46 -280 45 0 45 0 42 -42 -3 -43 -3 -43 -121 -46 -140 -3 -157 3 -157 58 0 40 0 40 45 40 45 0 45 0 46 68 1 37 3 123 5 192 2 69 3 162 4 208 0 82 0 82 45 82 45 0 45 0 45 -280z m312 3 c3 -278 3 -278 46 -281 43 -3 43 -3 40 -45 -3 -42 -3 -42 -118 -45 -134 -3 -170 7 -170 47 0 37 17 51 62 51 43 0 40 -26 39 305 -1 77 2 164 5 193 6 52 6 52 50 52 44 0 44 0 46 -277z m698 148 c0 -128 0 -128 58 -134 50 -5 61 -10 89 -42 24 -28 33 -50 39 -92 16 -130 -14 -214 -84 -232 -40 -11 -168 -18 -175 -11 -8 8 -18 626 -11 633 4 4 25 7 46 7 38 0 38 0 38 -129z m815 84 c0 -40 0 -40 -66 -43 -66 -3 -66 -3 -72 -160 -3 -86 -6 -208 -7 -271 0 -63 -3 -118 -6 -123 -3 -4 -23 -8 -45 -8 -39 0 -39 0 -39 325 0 326 0 326 118 323 117 -3 117 -3 117 -43z";
pp_polygon_t polygon = parse_svg_path(logo_svg_path);

uint64_t start = time_ms();

for(int i = 240; i <= 360; i += 10) {
// determine extreme bounds and scaling factor to fit on canvas
pp_rect_t bounds = pp_polygon_bounds(&polygon);
Expand Down Expand Up @@ -317,6 +322,10 @@ int main() {
draw_polygon(&polygon);
}

uint64_t end = time_ms();
printf("render time: %llums", end - start);



stbi_write_png("/tmp/out.png", WIDTH, HEIGHT, 4, (void *)buffer, WIDTH * sizeof(uint32_t));

Expand Down
58 changes: 32 additions & 26 deletions pretty-poly.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
// An easy way to render high quality text in embedded applications running
// on resource constrained microcontrollers such as the Cortex M0 and up.
//
// - renders polygons: concave, self-intersecting, multi contour, holes, etc.
// - Renders polygons: concave, self-intersecting, multi contour, holes, etc.
// - C17 header only library: simply copy the header file into your project
// - tile based renderer: low memory footprint, cache coherency
// - low memory usage: ~4kB of heap memory required
// - high speed on low resource platforms: optionally no floating point
// - antialiasing modes: X1 (none), X4 and X16 super sampling
// - bounds clipping: all results clipped to supplied clip rectangle
// - pixel format agnostic: renders a "tile" to blend into your framebuffer
// - support for hardware interpolators on rp2040 (thanks @MichaelBell!)
// - Tile based renderer: low memory footprint, cache coherency
// - Low memory usage: ~4kB of heap memory required
// - High speed on low resource platforms: optionally no floating point
// - Antialiasing modes: X1 (none), X4 and X16 super sampling
// - Bounds clipping: all results clipped to supplied clip rectangle
// - Pixel format agnostic: renders a "tile" to blend into your framebuffer
// - Support for hardware interpolators on rp2040 (thanks @MichaelBell!)
//
// Contributor bwaaaaaarks! 🦜
//
// @MichaelBell - lots of bug fixes, performance boosts, and suggestions.
// @gadgetoid - integrating into the PicoVector library and testing.

#pragma once

Expand All @@ -27,12 +32,16 @@
#define PP_COORD_TYPE float
#endif

#ifndef PP_MAX_INTERSECTIONS
#define PP_MAX_INTERSECTIONS 16
#ifndef PP_NODE_BUFFER_HEIGHT
#define PP_NODE_BUFFER_HEIGHT 64
#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 1024
#define PP_TILE_BUFFER_SIZE 4096
#endif

#if defined(PICO_ON_DEVICE) && PICO_ON_DEVICE
Expand All @@ -46,6 +55,10 @@
#define debug(...)
#endif

int _pp_max(int32_t a, int32_t b) { return a > b ? a : b; }
int _pp_min(int32_t a, int32_t b) { return a < b ? a : b; }
int32_t _pp_sign(int32_t v) {return ((uint32_t)-v >> 31) - ((uint32_t)v >> 31);}
void _pp_swap(int32_t *a, int32_t *b) {int32_t t = *a; *a = *b; *b = t;}

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -118,12 +131,6 @@ static void pp_transform(pp_mat3_t *transform);
}
#endif

// helpers
int _pp_max(int32_t a, int32_t b) { return a > b ? a : b; }
int _pp_min(int32_t a, int32_t b) { return a < b ? a : b; }
int32_t _pp_sign(int32_t v) {return ((uint32_t)-v >> 31) - ((uint32_t)v >> 31);}
void _pp_swap(int32_t *a, int32_t *b) {int32_t t = *a; *a = *b; *b = t;}

// pp_mat3_t implementation
static pp_mat3_t pp_mat3_identity() {
pp_mat3_t m; memset(&m, 0, sizeof(pp_mat3_t)); m.v00 = m.v11 = m.v22 = 1.0f; return m;}
Expand Down Expand Up @@ -214,8 +221,8 @@ pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m) {
}

// pp_tile_t implementation
int pp_tile_get_value(const pp_tile_t *tile, const int x, const int y) {
return tile->data[x + y * tile->stride] * (255 >> _pp_antialias >> _pp_antialias);
uint8_t pp_tile_get_value(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);
}

// pp_contour_t implementation
Expand Down Expand Up @@ -248,9 +255,8 @@ uint8_t tile_buffer[tile_buffer_size + 1];

// polygon node buffer handles at most 16 line intersections per scanline
// is this enough for cjk/emoji? (requires a 2kB buffer)
const uint32_t node_buffer_size = PP_MAX_INTERSECTIONS * 2;
int32_t nodes[node_buffer_size][PP_MAX_INTERSECTIONS * 2];
uint32_t node_counts[node_buffer_size];
int32_t nodes[PP_NODE_BUFFER_HEIGHT][PP_MAX_NODES_PER_SCANLINE * 2];
uint32_t node_counts[PP_NODE_BUFFER_HEIGHT];


void pp_clip(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
Expand All @@ -266,7 +272,7 @@ int32_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 = node_buffer_size >> _pp_antialias;
_pp_tile_height = PP_NODE_BUFFER_HEIGHT >> _pp_antialias;
_pp_tile_width = (int)(tile_buffer_size / _pp_tile_height);
}

Expand Down Expand Up @@ -302,13 +308,13 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
}

// Early out if line is completely outside the tile, or has no lines
if (ey < 0 || sy >= (int)node_buffer_size || sy == ey) return;
if (ey < 0 || sy >= (int)PP_NODE_BUFFER_HEIGHT || 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
int y = _pp_max(0, sy);
int count = _pp_min((int)node_buffer_size, ey) - y;
int count = _pp_min((int)PP_NODE_BUFFER_HEIGHT, ey) - y;

// Handle cases where x is completely off to one side or other
if (_pp_max(sx, ex) <= 0) {
Expand Down Expand Up @@ -441,7 +447,7 @@ pp_rect_t render_nodes(uint8_t *buffer, pp_rect_t *tb) {
PP_COORD_TYPE aa_scale = (PP_COORD_TYPE)(1 << _pp_antialias);
int anitialias_mask = (1 << _pp_antialias) - 1;

for(uint32_t y = 0; y < node_buffer_size; y++) {
for(uint32_t y = 0; y < PP_NODE_BUFFER_HEIGHT; y++) {
if(node_counts[y] == 0) {
if (y == rb.y) ++rb.y;
continue;
Expand Down

0 comments on commit 2cbe061

Please sign in to comment.