eliminate recursion from polyfill #2300

This commit is contained in:
nick black 2021-11-01 22:48:32 -05:00
parent 2ce3c0ef4e
commit 8f9608eb19

View File

@ -1262,25 +1262,72 @@ int ncvisual_at_yx(const ncvisual* n, int y, int x, uint32_t* pixel){
return 0; return 0;
} }
// a neighbor on which to polyfill. by the time we get to it, it might or
// might not have been filled in. if so, discard immediately. otherwise,
// check self, and if valid, push all neighbors.
struct topolyfill {
int y, x;
struct topolyfill* next;
};
static inline struct topolyfill*
create_polyfill_op(int y, int x, struct topolyfill** stack){
struct topolyfill* n = malloc(sizeof(*n));
if(n){
n->y = y;
n->x = x;
n->next = *stack;
*stack = n;
}
return n;
}
// originally i wrote this recursively, at which point it promptly began
// exploding once i multithreaded the [yield] demo. hence the clumsy stack
// and hand-rolled iteration. alas, poor yorick!
static int static int
ncvisual_polyfill_recurse(ncvisual* n, int y, int x, uint32_t rgba, uint32_t match){ ncvisual_polyfill_core(ncvisual* n, int y, int x, uint32_t rgba, uint32_t match){
if(y < 0 || y >= n->pixy){ struct topolyfill* stack = malloc(sizeof(*stack));
return 0; if(stack == NULL){
return -1;
} }
if(x < 0 || x >= n->pixx){ stack->y = y;
return 0; stack->x = x;
} stack->next = NULL;
uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x]; int ret = 0;
if(*pixel != match || *pixel == rgba){ do{
return 0; struct topolyfill* s = stack;
} stack = s->next;
// fprintf(stderr, "%d/%d: setting %08x to %08x\n", y, x, *pixel, rgba); y = s->y;
*pixel = rgba; x = s->x;
int ret = 1; uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
ret += ncvisual_polyfill_recurse(n, y - 1, x, rgba, match); if(*pixel == match && *pixel != rgba){
ret += ncvisual_polyfill_recurse(n, y + 1, x, rgba, match); ++ret;
ret += ncvisual_polyfill_recurse(n, y, x - 1, rgba, match); // fprintf(stderr, "%d/%d: setting %08x to %08x\n", y, x, *pixel, rgba);
ret += ncvisual_polyfill_recurse(n, y, x + 1, rgba, match); *pixel = rgba;
if(y){
if(create_polyfill_op(y - 1, x, &stack) == NULL){
return -1;
}
}
if(y + 1 < n->pixy){
if(create_polyfill_op(y + 1, x, &stack) == NULL){
return -1;
}
}
if(x){
if(create_polyfill_op(y, x - 1, &stack) == NULL){
return -1;
}
}
if(x + 1 < n->pixx){
if(create_polyfill_op(y, x + 1, &stack) == NULL){
return -1;
}
}
}
free(s);
}while(stack);
return ret; return ret;
} }
@ -1292,7 +1339,7 @@ int ncvisual_polyfill_yx(ncvisual* n, int y, int x, uint32_t rgba){
return -1; return -1;
} }
uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x]; uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
return ncvisual_polyfill_recurse(n, y, x, rgba, *pixel); return ncvisual_polyfill_core(n, y, x, rgba, *pixel);
} }
bool notcurses_canopen_images(const notcurses* nc __attribute__ ((unused))){ bool notcurses_canopen_images(const notcurses* nc __attribute__ ((unused))){