mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
Implement generic 4x2 blitter
This commit is contained in:
parent
bf9c31db27
commit
531bdd0e8b
583
src/lib/blit.c
583
src/lib/blit.c
@ -711,447 +711,87 @@ sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
return total;
|
||||
}
|
||||
|
||||
// Bit is *set* where octant *is*:
|
||||
// Bit is set where octant is present:
|
||||
// 0 1
|
||||
// 2 3
|
||||
// 4 5
|
||||
// 6 7
|
||||
// Same as NCOCTBLOCKS but as array of characters
|
||||
static const char* const octant_egcs[256] = {
|
||||
"\x20",
|
||||
"\U0001CEA8",
|
||||
"\U0001CEAB",
|
||||
"\U0001FB82",
|
||||
"\U0001CD00",
|
||||
"\U00002598",
|
||||
"\U0001CD01",
|
||||
"\U0001CD02",
|
||||
"\U0001CD03",
|
||||
"\U0001CD04",
|
||||
"\U0000259D",
|
||||
"\U0001CD05",
|
||||
"\U0001CD06",
|
||||
"\U0001CD07",
|
||||
"\U0001CD08",
|
||||
"\U00002580",
|
||||
"\U0001CD09",
|
||||
"\U0001CD0A",
|
||||
"\U0001CD0B",
|
||||
"\U0001CD0C",
|
||||
"\U0001FBE6",
|
||||
"\U0001CD0D",
|
||||
"\U0001CD0E",
|
||||
"\U0001CD0F",
|
||||
"\U0001CD10",
|
||||
"\U0001CD11",
|
||||
"\U0001CD12",
|
||||
"\U0001CD13",
|
||||
"\U0001CD14",
|
||||
"\U0001CD15",
|
||||
"\U0001CD16",
|
||||
"\U0001CD17",
|
||||
"\U0001CD18",
|
||||
"\U0001CD19",
|
||||
"\U0001CD1A",
|
||||
"\U0001CD1B",
|
||||
"\U0001CD1C",
|
||||
"\U0001CD1D",
|
||||
"\U0001CD1E",
|
||||
"\U0001CD1F",
|
||||
"\U0001FBE7",
|
||||
"\U0001CD20",
|
||||
"\U0001CD21",
|
||||
"\U0001CD22",
|
||||
"\U0001CD23",
|
||||
"\U0001CD24",
|
||||
"\U0001CD25",
|
||||
"\U0001CD26",
|
||||
"\U0001CD27",
|
||||
"\U0001CD28",
|
||||
"\U0001CD29",
|
||||
"\U0001CD2A",
|
||||
"\U0001CD2B",
|
||||
"\U0001CD2C",
|
||||
"\U0001CD2D",
|
||||
"\U0001CD2E",
|
||||
"\U0001CD2F",
|
||||
"\U0001CD30",
|
||||
"\U0001CD31",
|
||||
"\U0001CD32",
|
||||
"\U0001CD33",
|
||||
"\U0001CD34",
|
||||
"\U0001CD35",
|
||||
"\U0001FB85",
|
||||
"\U0001CEA3",
|
||||
"\U0001CD36",
|
||||
"\U0001CD37",
|
||||
"\U0001CD38",
|
||||
"\U0001CD39",
|
||||
"\U0001CD3A",
|
||||
"\U0001CD3B",
|
||||
"\U0001CD3C",
|
||||
"\U0001CD3D",
|
||||
"\U0001CD3E",
|
||||
"\U0001CD3F",
|
||||
"\U0001CD40",
|
||||
"\U0001CD41",
|
||||
"\U0001CD42",
|
||||
"\U0001CD43",
|
||||
"\U0001CD44",
|
||||
"\U00002596",
|
||||
"\U0001CD45",
|
||||
"\U0001CD46",
|
||||
"\U0001CD47",
|
||||
"\U0001CD48",
|
||||
"\U0000258C",
|
||||
"\U0001CD49",
|
||||
"\U0001CD4A",
|
||||
"\U0001CD4B",
|
||||
"\U0001CD4C",
|
||||
"\U0000259E",
|
||||
"\U0001CD4D",
|
||||
"\U0001CD4E",
|
||||
"\U0001CD4F",
|
||||
"\U0001CD50",
|
||||
"\U0000259B",
|
||||
"\U0001CD51",
|
||||
"\U0001CD52",
|
||||
"\U0001CD53",
|
||||
"\U0001CD54",
|
||||
"\U0001CD55",
|
||||
"\U0001CD56",
|
||||
"\U0001CD57",
|
||||
"\U0001CD58",
|
||||
"\U0001CD59",
|
||||
"\U0001CD5A",
|
||||
"\U0001CD5B",
|
||||
"\U0001CD5C",
|
||||
"\U0001CD5D",
|
||||
"\U0001CD5E",
|
||||
"\U0001CD5F",
|
||||
"\U0001CD60",
|
||||
"\U0001CD61",
|
||||
"\U0001CD62",
|
||||
"\U0001CD63",
|
||||
"\U0001CD64",
|
||||
"\U0001CD65",
|
||||
"\U0001CD66",
|
||||
"\U0001CD67",
|
||||
"\U0001CD68",
|
||||
"\U0001CD69",
|
||||
"\U0001CD6A",
|
||||
"\U0001CD6B",
|
||||
"\U0001CD6C",
|
||||
"\U0001CD6D",
|
||||
"\U0001CD6E",
|
||||
"\U0001CD6F",
|
||||
"\U0001CD70",
|
||||
"\U0001CEA0",
|
||||
"\U0001CD71",
|
||||
"\U0001CD72",
|
||||
"\U0001CD73",
|
||||
"\U0001CD74",
|
||||
"\U0001CD75",
|
||||
"\U0001CD76",
|
||||
"\U0001CD77",
|
||||
"\U0001CD78",
|
||||
"\U0001CD79",
|
||||
"\U0001CD7A",
|
||||
"\U0001CD7B",
|
||||
"\U0001CD7C",
|
||||
"\U0001CD7D",
|
||||
"\U0001CD7E",
|
||||
"\U0001CD7F",
|
||||
"\U0001CD80",
|
||||
"\U0001CD81",
|
||||
"\U0001CD82",
|
||||
"\U0001CD83",
|
||||
"\U0001CD84",
|
||||
"\U0001CD85",
|
||||
"\U0001CD86",
|
||||
"\U0001CD87",
|
||||
"\U0001CD88",
|
||||
"\U0001CD89",
|
||||
"\U0001CD8A",
|
||||
"\U0001CD8B",
|
||||
"\U0001CD8C",
|
||||
"\U0001CD8D",
|
||||
"\U0001CD8E",
|
||||
"\U0001CD8F",
|
||||
"\U00002597",
|
||||
"\U0001CD90",
|
||||
"\U0001CD91",
|
||||
"\U0001CD92",
|
||||
"\U0001CD93",
|
||||
"\U0000259A",
|
||||
"\U0001CD94",
|
||||
"\U0001CD95",
|
||||
"\U0001CD96",
|
||||
"\U0001CD97",
|
||||
"\U00002590",
|
||||
"\U0001CD98",
|
||||
"\U0001CD99",
|
||||
"\U0001CD9A",
|
||||
"\U0001CD9B",
|
||||
"\U0000259C",
|
||||
"\U0001CD9C",
|
||||
"\U0001CD9D",
|
||||
"\U0001CD9E",
|
||||
"\U0001CD9F",
|
||||
"\U0001CDA0",
|
||||
"\U0001CDA1",
|
||||
"\U0001CDA2",
|
||||
"\U0001CDA3",
|
||||
"\U0001CDA4",
|
||||
"\U0001CDA5",
|
||||
"\U0001CDA6",
|
||||
"\U0001CDA7",
|
||||
"\U0001CDA8",
|
||||
"\U0001CDA9",
|
||||
"\U0001CDAA",
|
||||
"\U0001CDAB",
|
||||
"\U00002582",
|
||||
"\U0001CDAC",
|
||||
"\U0001CDAD",
|
||||
"\U0001CDAE",
|
||||
"\U0001CDAF",
|
||||
"\U0001CDB0",
|
||||
"\U0001CDB1",
|
||||
"\U0001CDB2",
|
||||
"\U0001CDB3",
|
||||
"\U0001CDB4",
|
||||
"\U0001CDB5",
|
||||
"\U0001CDB6",
|
||||
"\U0001CDB7",
|
||||
"\U0001CDB8",
|
||||
"\U0001CDB9",
|
||||
"\U0001CDBA",
|
||||
"\U0001CDBB",
|
||||
"\U0001CDBC",
|
||||
"\U0001CDBD",
|
||||
"\U0001CDBE",
|
||||
"\U0001CDBF",
|
||||
"\U0001CDC0",
|
||||
"\U0001CDC1",
|
||||
"\U0001CDC2",
|
||||
"\U0001CDC3",
|
||||
"\U0001CDC4",
|
||||
"\U0001CDC5",
|
||||
"\U0001CDC6",
|
||||
"\U0001CDC7",
|
||||
"\U0001CDC8",
|
||||
"\U0001CDC9",
|
||||
"\U0001CDCA",
|
||||
"\U0001CDCB",
|
||||
"\U0001CDCC",
|
||||
"\U0001CDCD",
|
||||
"\U0001CDCE",
|
||||
"\U0001CDCF",
|
||||
"\U0001CDD0",
|
||||
"\U0001CDD1",
|
||||
"\U0001CDD2",
|
||||
"\U0001CDD3",
|
||||
"\U0001CDD4",
|
||||
"\U0001CDD5",
|
||||
"\U0001CDD6",
|
||||
"\U0001CDD7",
|
||||
"\U0001CDD8",
|
||||
"\U0001CDD9",
|
||||
"\U0001CDDA",
|
||||
"\U00002584",
|
||||
"\U0001CDDB",
|
||||
"\U0001CDDC",
|
||||
"\U0001CDDD",
|
||||
"\U0001CDDE",
|
||||
"\U00002599",
|
||||
"\U0001CDDF",
|
||||
"\U0001CDE0",
|
||||
"\U0001CDE1",
|
||||
"\U0001CDE2",
|
||||
"\U0000259F",
|
||||
"\U0001CDE3",
|
||||
"\U00002586",
|
||||
"\U0001CDE4",
|
||||
"\U0001CDE5",
|
||||
"\U00002588",
|
||||
// Same as NCOCTBLOCKS but as array of fixed-width strings
|
||||
static const char octant_egcs[256][5] = {
|
||||
"\x20", "\U0001CEA8", "\U0001CEAB", "\U0001FB82", "\U0001CD00", "\U00002598", "\U0001CD01", "\U0001CD02",
|
||||
"\U0001CD03", "\U0001CD04", "\U0000259D", "\U0001CD05", "\U0001CD06", "\U0001CD07", "\U0001CD08", "\U00002580",
|
||||
"\U0001CD09", "\U0001CD0A", "\U0001CD0B", "\U0001CD0C", "\U0001FBE6", "\U0001CD0D", "\U0001CD0E", "\U0001CD0F",
|
||||
"\U0001CD10", "\U0001CD11", "\U0001CD12", "\U0001CD13", "\U0001CD14", "\U0001CD15", "\U0001CD16", "\U0001CD17",
|
||||
"\U0001CD18", "\U0001CD19", "\U0001CD1A", "\U0001CD1B", "\U0001CD1C", "\U0001CD1D", "\U0001CD1E", "\U0001CD1F",
|
||||
"\U0001FBE7", "\U0001CD20", "\U0001CD21", "\U0001CD22", "\U0001CD23", "\U0001CD24", "\U0001CD25", "\U0001CD26",
|
||||
"\U0001CD27", "\U0001CD28", "\U0001CD29", "\U0001CD2A", "\U0001CD2B", "\U0001CD2C", "\U0001CD2D", "\U0001CD2E",
|
||||
"\U0001CD2F", "\U0001CD30", "\U0001CD31", "\U0001CD32", "\U0001CD33", "\U0001CD34", "\U0001CD35", "\U0001FB85",
|
||||
"\U0001CEA3", "\U0001CD36", "\U0001CD37", "\U0001CD38", "\U0001CD39", "\U0001CD3A", "\U0001CD3B", "\U0001CD3C",
|
||||
"\U0001CD3D", "\U0001CD3E", "\U0001CD3F", "\U0001CD40", "\U0001CD41", "\U0001CD42", "\U0001CD43", "\U0001CD44",
|
||||
"\U00002596", "\U0001CD45", "\U0001CD46", "\U0001CD47", "\U0001CD48", "\U0000258C", "\U0001CD49", "\U0001CD4A",
|
||||
"\U0001CD4B", "\U0001CD4C", "\U0000259E", "\U0001CD4D", "\U0001CD4E", "\U0001CD4F", "\U0001CD50", "\U0000259B",
|
||||
"\U0001CD51", "\U0001CD52", "\U0001CD53", "\U0001CD54", "\U0001CD55", "\U0001CD56", "\U0001CD57", "\U0001CD58",
|
||||
"\U0001CD59", "\U0001CD5A", "\U0001CD5B", "\U0001CD5C", "\U0001CD5D", "\U0001CD5E", "\U0001CD5F", "\U0001CD60",
|
||||
"\U0001CD61", "\U0001CD62", "\U0001CD63", "\U0001CD64", "\U0001CD65", "\U0001CD66", "\U0001CD67", "\U0001CD68",
|
||||
"\U0001CD69", "\U0001CD6A", "\U0001CD6B", "\U0001CD6C", "\U0001CD6D", "\U0001CD6E", "\U0001CD6F", "\U0001CD70",
|
||||
"\U0001CEA0", "\U0001CD71", "\U0001CD72", "\U0001CD73", "\U0001CD74", "\U0001CD75", "\U0001CD76", "\U0001CD77",
|
||||
"\U0001CD78", "\U0001CD79", "\U0001CD7A", "\U0001CD7B", "\U0001CD7C", "\U0001CD7D", "\U0001CD7E", "\U0001CD7F",
|
||||
"\U0001CD80", "\U0001CD81", "\U0001CD82", "\U0001CD83", "\U0001CD84", "\U0001CD85", "\U0001CD86", "\U0001CD87",
|
||||
"\U0001CD88", "\U0001CD89", "\U0001CD8A", "\U0001CD8B", "\U0001CD8C", "\U0001CD8D", "\U0001CD8E", "\U0001CD8F",
|
||||
"\U00002597", "\U0001CD90", "\U0001CD91", "\U0001CD92", "\U0001CD93", "\U0000259A", "\U0001CD94", "\U0001CD95",
|
||||
"\U0001CD96", "\U0001CD97", "\U00002590", "\U0001CD98", "\U0001CD99", "\U0001CD9A", "\U0001CD9B", "\U0000259C",
|
||||
"\U0001CD9C", "\U0001CD9D", "\U0001CD9E", "\U0001CD9F", "\U0001CDA0", "\U0001CDA1", "\U0001CDA2", "\U0001CDA3",
|
||||
"\U0001CDA4", "\U0001CDA5", "\U0001CDA6", "\U0001CDA7", "\U0001CDA8", "\U0001CDA9", "\U0001CDAA", "\U0001CDAB",
|
||||
"\U00002582", "\U0001CDAC", "\U0001CDAD", "\U0001CDAE", "\U0001CDAF", "\U0001CDB0", "\U0001CDB1", "\U0001CDB2",
|
||||
"\U0001CDB3", "\U0001CDB4", "\U0001CDB5", "\U0001CDB6", "\U0001CDB7", "\U0001CDB8", "\U0001CDB9", "\U0001CDBA",
|
||||
"\U0001CDBB", "\U0001CDBC", "\U0001CDBD", "\U0001CDBE", "\U0001CDBF", "\U0001CDC0", "\U0001CDC1", "\U0001CDC2",
|
||||
"\U0001CDC3", "\U0001CDC4", "\U0001CDC5", "\U0001CDC6", "\U0001CDC7", "\U0001CDC8", "\U0001CDC9", "\U0001CDCA",
|
||||
"\U0001CDCB", "\U0001CDCC", "\U0001CDCD", "\U0001CDCE", "\U0001CDCF", "\U0001CDD0", "\U0001CDD1", "\U0001CDD2",
|
||||
"\U0001CDD3", "\U0001CDD4", "\U0001CDD5", "\U0001CDD6", "\U0001CDD7", "\U0001CDD8", "\U0001CDD9", "\U0001CDDA",
|
||||
"\U00002584", "\U0001CDDB", "\U0001CDDC", "\U0001CDDD", "\U0001CDDE", "\U00002599", "\U0001CDDF", "\U0001CDE0",
|
||||
"\U0001CDE1", "\U0001CDE2", "\U0000259F", "\U0001CDE3", "\U00002586", "\U0001CDE4", "\U0001CDE5", "\U00002588",
|
||||
};
|
||||
|
||||
// Solve for the cell rendered by this 4x2 sample. None of the input pixels may
|
||||
// be transparent (that ought already have been handled). We use exhaustive
|
||||
// search, which might be quite computationally intensive for the worst case
|
||||
// (all eight pixels are different colors). We want to solve for the 2-partition
|
||||
// of pixels that minimizes total source distance from the resulting lerps.
|
||||
static const char*
|
||||
oct_solver(const uint32_t rgbas[8], uint64_t* channels, unsigned blendcolors,
|
||||
unsigned nointerpolate){
|
||||
// Each element within the set of 256 has an inverse element within
|
||||
// the set, for which we would calculate the same total differences,
|
||||
// so just handle the first 128.
|
||||
//
|
||||
// We loop over the bitstrings, dividing the pixels into two sets,
|
||||
// and then taking a general lerp over each set. we then compute the
|
||||
// sum of absolute differences, and see if it's the new minimum.
|
||||
int best = -1;
|
||||
uint32_t mindiff = UINT_MAX;
|
||||
for(size_t glyph = 0; glyph < 128; ++glyph){
|
||||
unsigned rsum0 = 0, rsum1 = 0;
|
||||
unsigned gsum0 = 0, gsum1 = 0;
|
||||
unsigned bsum0 = 0, bsum1 = 0;
|
||||
int insum = 0;
|
||||
int outsum = 0;
|
||||
for(unsigned mask = 0 ; mask < 8 ; ++mask){
|
||||
if(glyph & (1u << mask)){
|
||||
if(!nointerpolate || !insum){
|
||||
rsum0 += ncpixel_r(rgbas[mask]);
|
||||
gsum0 += ncpixel_g(rgbas[mask]);
|
||||
bsum0 += ncpixel_b(rgbas[mask]);
|
||||
++insum;
|
||||
}
|
||||
}else{
|
||||
if(!nointerpolate || !outsum){
|
||||
rsum1 += ncpixel_r(rgbas[mask]);
|
||||
gsum1 += ncpixel_g(rgbas[mask]);
|
||||
bsum1 += ncpixel_b(rgbas[mask]);
|
||||
++outsum;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t l0 = generalerp(rsum0, gsum0, bsum0, insum);
|
||||
uint32_t l1 = generalerp(rsum1, gsum1, bsum1, outsum);
|
||||
uint32_t totaldiff = 0;
|
||||
for(unsigned mask = 0 ; mask < 8 ; ++mask){
|
||||
unsigned r, g, b;
|
||||
if(glyph & (1u << mask)){
|
||||
ncchannel_rgb8(l0, &r, &g, &b);
|
||||
}else{
|
||||
ncchannel_rgb8(l1, &r, &g, &b);
|
||||
}
|
||||
uint32_t rdiff = rgb_diff(ncpixel_r(rgbas[mask]), ncpixel_g(rgbas[mask]),
|
||||
ncpixel_b(rgbas[mask]), r, g, b);
|
||||
totaldiff += rdiff;
|
||||
}
|
||||
if(totaldiff < mindiff){
|
||||
mindiff = totaldiff;
|
||||
best = glyph;
|
||||
ncchannels_set_fchannel(channels, l0);
|
||||
ncchannels_set_bchannel(channels, l1);
|
||||
}
|
||||
if(totaldiff == 0){ // can't beat that!
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(best >= 0 && best < 128);
|
||||
if(blendcolors){
|
||||
ncchannels_set_fg_alpha(channels, NCALPHA_BLEND);
|
||||
ncchannels_set_bg_alpha(channels, NCALPHA_BLEND);
|
||||
}
|
||||
return octant_egcs[best];
|
||||
}
|
||||
|
||||
static const char*
|
||||
oct_trans_check(nccell* c, const uint32_t rgbas[8], unsigned blendcolors,
|
||||
uint32_t transcolor, unsigned nointerpolate){
|
||||
unsigned transstring = 0;
|
||||
unsigned r = 0, g = 0, b = 0;
|
||||
unsigned div = 0;
|
||||
for(unsigned mask = 0 ; mask < 8 ; ++mask){
|
||||
if(rgba_trans_p(rgbas[mask], transcolor)){
|
||||
transstring |= (1u << mask);
|
||||
}else if(!nointerpolate || !div){
|
||||
r += ncpixel_r(rgbas[mask]);
|
||||
g += ncpixel_g(rgbas[mask]);
|
||||
b += ncpixel_b(rgbas[mask]);
|
||||
++div;
|
||||
}
|
||||
}
|
||||
if(transstring == 0){ // there was no transparency
|
||||
return NULL;
|
||||
}
|
||||
nccell_set_bg_alpha(c, NCALPHA_TRANSPARENT);
|
||||
// there were some transparent pixels. since they get priority, the foreground
|
||||
// is just a general lerp across non-transparent pixels.
|
||||
const char* egc = octant_egcs[transstring ^ 0xff];
|
||||
nccell_set_bg_alpha(c, NCALPHA_TRANSPARENT);
|
||||
//fprintf(stderr, "transtring: %u egc: %s\n", transtring, egc);
|
||||
if(*egc == ' '){ // entirely transparent
|
||||
nccell_set_fg_alpha(c, NCALPHA_TRANSPARENT);
|
||||
return "";
|
||||
}else{ // partially transparent, thus div >= 1
|
||||
//fprintf(stderr, "div: %u r: %u g: %u b: %u\n", div, r, g, b);
|
||||
cell_set_fchannel(c, generalerp(r, g, b, div));
|
||||
if(blendcolors){
|
||||
nccell_set_fg_alpha(c, NCALPHA_BLEND);
|
||||
}
|
||||
cell_set_blitquadrants(c, !(transstring & 5u), !(transstring & 10u),
|
||||
!(transstring & 20u), !(transstring & 40u));
|
||||
}
|
||||
//fprintf(stderr, "OCT-BQ: 0x%x\n", cell_blittedquadrants(c));
|
||||
return egc;
|
||||
}
|
||||
|
||||
// octant blitter. maps 4x2 to each cell. since we only have two colors at
|
||||
// our disposal (foreground and background), we lose some fidelity.
|
||||
static inline int
|
||||
octant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
const blitterargs* bargs){
|
||||
const unsigned nointerpolate = bargs->flags & NCVISUAL_OPTION_NOINTERPOLATE;
|
||||
const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
|
||||
unsigned dimy, dimx, x, y;
|
||||
int total = 0; // number of cells written
|
||||
ncplane_dim_yx(nc, &dimy, &dimx);
|
||||
//fprintf(stderr, "octblitter %dx%d -> %d/%d+%d/%d\n", leny, lenx, dimy, dimx, bargs->u.cell.placey, bargs->u.cell.placex);
|
||||
const unsigned char* dat = data;
|
||||
int visy = bargs->begy;
|
||||
for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += 4){
|
||||
if(ncplane_cursor_move_yx(nc, y, bargs->u.cell.placex < 0 ? 0 : bargs->u.cell.placex)){
|
||||
return -1;
|
||||
}
|
||||
int visx = bargs->begx;
|
||||
for(x = bargs->u.cell.placex ; visx < (bargs->begx + lenx) && x < dimx ; ++x, visx += 2){
|
||||
uint32_t rgbas[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
memcpy(&rgbas[0], (dat + (linesize * visy) + (visx * 4)), sizeof(*rgbas));
|
||||
if(visx < bargs->begx + lenx - 1){
|
||||
memcpy(&rgbas[1], (dat + (linesize * visy) + ((visx + 1) * 4)), sizeof(*rgbas));
|
||||
if(visy < bargs->begy + leny - 1){
|
||||
memcpy(&rgbas[3], (dat + (linesize * (visy + 1)) + ((visx + 1) * 4)), sizeof(*rgbas));
|
||||
if(visy < bargs->begy + leny - 2){
|
||||
memcpy(&rgbas[5], (dat + (linesize * (visy + 2)) + ((visx + 1) * 4)), sizeof(*rgbas));
|
||||
if(visy < bargs->begy + leny - 3){
|
||||
memcpy(&rgbas[7], (dat + (linesize * (visy + 3)) + ((visx + 1) * 4)), sizeof(*rgbas));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(visy < bargs->begy + leny - 1){
|
||||
memcpy(&rgbas[2], (dat + (linesize * (visy + 1)) + (visx * 4)), sizeof(*rgbas));
|
||||
if(visy < bargs->begy + leny - 2){
|
||||
memcpy(&rgbas[4], (dat + (linesize * (visy + 2)) + (visx * 4)), sizeof(*rgbas));
|
||||
if(visy < bargs->begy + leny - 3){
|
||||
memcpy(&rgbas[6], (dat + (linesize * (visy + 3)) + (visx * 4)), sizeof(*rgbas));
|
||||
}
|
||||
}
|
||||
}
|
||||
nccell* c = ncplane_cell_ref_yx(nc, y, x);
|
||||
c->channels = 0;
|
||||
c->stylemask = 0;
|
||||
const char* egc = oct_trans_check(c, rgbas, blendcolors, bargs->transcolor, nointerpolate);
|
||||
if(egc == NULL){ // no transparency; run a full solver
|
||||
egc = oct_solver(rgbas, &c->channels, blendcolors, nointerpolate);
|
||||
cell_set_blitquadrants(c, 1, 1, 1, 1);
|
||||
}
|
||||
//fprintf(stderr, "oct EGC: %s channels: %016lx\n", egc, c->channels);
|
||||
if(*egc){
|
||||
if(pool_blit_direct(&nc->pool, c, egc, strlen(egc), 1) <= 0){
|
||||
return -1;
|
||||
}
|
||||
++total;
|
||||
}else{
|
||||
nccell_release(nc, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
// Bit is set where Braille dot is present:
|
||||
// 0 1
|
||||
// 2 3
|
||||
// 4 5
|
||||
// 6 7
|
||||
// Similar to NCBRAILLEEGCS, but in a different order since we number the bits differently
|
||||
static const char braille_egcs[256][5] = {
|
||||
"\u2800", "\u2801", "\u2808", "\u2809", "\u2802", "\u2803", "\u280a", "\u280b",
|
||||
"\u2810", "\u2811", "\u2818", "\u2819", "\u2812", "\u2813", "\u281a", "\u281b",
|
||||
"\u2804", "\u2805", "\u280c", "\u280d", "\u2806", "\u2807", "\u280e", "\u280f",
|
||||
"\u2814", "\u2815", "\u281c", "\u281d", "\u2816", "\u2817", "\u281e", "\u281f",
|
||||
"\u2820", "\u2821", "\u2828", "\u2829", "\u2822", "\u2823", "\u282a", "\u282b",
|
||||
"\u2830", "\u2831", "\u2838", "\u2839", "\u2832", "\u2833", "\u283a", "\u283b",
|
||||
"\u2824", "\u2825", "\u282c", "\u282d", "\u2826", "\u2827", "\u282e", "\u282f",
|
||||
"\u2834", "\u2835", "\u283c", "\u283d", "\u2836", "\u2837", "\u283e", "\u283f",
|
||||
"\u2840", "\u2841", "\u2848", "\u2849", "\u2842", "\u2843", "\u284a", "\u284b",
|
||||
"\u2850", "\u2851", "\u2858", "\u2859", "\u2852", "\u2853", "\u285a", "\u285b",
|
||||
"\u2844", "\u2845", "\u284c", "\u284d", "\u2846", "\u2847", "\u284e", "\u284f",
|
||||
"\u2854", "\u2855", "\u285c", "\u285d", "\u2856", "\u2857", "\u285e", "\u285f",
|
||||
"\u2860", "\u2861", "\u2868", "\u2869", "\u2862", "\u2863", "\u286a", "\u286b",
|
||||
"\u2870", "\u2871", "\u2878", "\u2879", "\u2872", "\u2873", "\u287a", "\u287b",
|
||||
"\u2864", "\u2865", "\u286c", "\u286d", "\u2866", "\u2867", "\u286e", "\u286f",
|
||||
"\u2874", "\u2875", "\u287c", "\u287d", "\u2876", "\u2877", "\u287e", "\u287f",
|
||||
"\u2880", "\u2881", "\u2888", "\u2889", "\u2882", "\u2883", "\u288a", "\u288b",
|
||||
"\u2890", "\u2891", "\u2898", "\u2899", "\u2892", "\u2893", "\u289a", "\u289b",
|
||||
"\u2884", "\u2885", "\u288c", "\u288d", "\u2886", "\u2887", "\u288e", "\u288f",
|
||||
"\u2894", "\u2895", "\u289c", "\u289d", "\u2896", "\u2897", "\u289e", "\u289f",
|
||||
"\u28a0", "\u28a1", "\u28a8", "\u28a9", "\u28a2", "\u28a3", "\u28aa", "\u28ab",
|
||||
"\u28b0", "\u28b1", "\u28b8", "\u28b9", "\u28b2", "\u28b3", "\u28ba", "\u28bb",
|
||||
"\u28a4", "\u28a5", "\u28ac", "\u28ad", "\u28a6", "\u28a7", "\u28ae", "\u28af",
|
||||
"\u28b4", "\u28b5", "\u28bc", "\u28bd", "\u28b6", "\u28b7", "\u28be", "\u28bf",
|
||||
"\u28c0", "\u28c1", "\u28c8", "\u28c9", "\u28c2", "\u28c3", "\u28ca", "\u28cb",
|
||||
"\u28d0", "\u28d1", "\u28d8", "\u28d9", "\u28d2", "\u28d3", "\u28da", "\u28db",
|
||||
"\u28c4", "\u28c5", "\u28cc", "\u28cd", "\u28c6", "\u28c7", "\u28ce", "\u28cf",
|
||||
"\u28d4", "\u28d5", "\u28dc", "\u28dd", "\u28d6", "\u28d7", "\u28de", "\u28df",
|
||||
"\u28e0", "\u28e1", "\u28e8", "\u28e9", "\u28e2", "\u28e3", "\u28ea", "\u28eb",
|
||||
"\u28f0", "\u28f1", "\u28f8", "\u28f9", "\u28f2", "\u28f3", "\u28fa", "\u28fb",
|
||||
"\u28e4", "\u28e5", "\u28ec", "\u28ed", "\u28e6", "\u28e7", "\u28ee", "\u28ef",
|
||||
"\u28f4", "\u28f5", "\u28fc", "\u28fd", "\u28f6", "\u28f7", "\u28fe", "\u28ff",
|
||||
};
|
||||
|
||||
// fold the r, g, and b components of the pixel into *r, *g, and *b, and
|
||||
// increment *foldcount
|
||||
@ -1164,13 +804,14 @@ fold_rgb8(unsigned* restrict r, unsigned* restrict g, unsigned* restrict b,
|
||||
++*foldcount;
|
||||
}
|
||||
|
||||
// Braille blitter. maps 4x2 to each cell. since we only have one color at
|
||||
// our disposal (foreground), we lose some fidelity. this is optimal for
|
||||
// visuals with only two colors in a given area, as it packs lots of
|
||||
// resolution. always transparent background.
|
||||
// generic 4x2 blitter, used for octant and Braille. maps 4x2 to each
|
||||
// cell. since we only have one color at our disposal (foreground), we
|
||||
// lose some fidelity. this is optimal for visuals with only two
|
||||
// colors in a given area, as it packs lots of resolution. always
|
||||
// transparent background.
|
||||
static inline int
|
||||
braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
const blitterargs* bargs){
|
||||
blit_4x2(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
const blitterargs* bargs, const char egcs[256][5]){
|
||||
const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND;
|
||||
unsigned dimy, dimx, x, y;
|
||||
int total = 0; // number of cells written
|
||||
@ -1216,32 +857,32 @@ braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
}
|
||||
}
|
||||
}
|
||||
// braille block is ordered (where 1 is the LSB)
|
||||
// 1 4
|
||||
// 2 5
|
||||
// 3 6
|
||||
// 7 8
|
||||
// 4x2 block is ordered (where 0 is the LSB)
|
||||
// 0 1
|
||||
// 2 3
|
||||
// 4 5
|
||||
// 6 7
|
||||
// FIXME fold this into the above?
|
||||
if(!rgba_trans_p(*rgbbase_l0, bargs->transcolor)){
|
||||
egcidx |= 1u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_l0, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_l1, bargs->transcolor)){
|
||||
egcidx |= 2u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_l1, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_l2, bargs->transcolor)){
|
||||
egcidx |= 4u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_l2, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_r0, bargs->transcolor)){
|
||||
egcidx |= 8u;
|
||||
egcidx |= 2u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_r0, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_l1, bargs->transcolor)){
|
||||
egcidx |= 4u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_l1, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_r1, bargs->transcolor)){
|
||||
egcidx |= 16u;
|
||||
egcidx |= 8u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_r1, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_l2, bargs->transcolor)){
|
||||
egcidx |= 16u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_l2, &blends);
|
||||
}
|
||||
if(!rgba_trans_p(*rgbbase_r2, bargs->transcolor)){
|
||||
egcidx |= 32u;
|
||||
fold_rgb8(&r, &g, &b, rgbbase_r2, &blends);
|
||||
@ -1274,11 +915,7 @@ braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
if(blends){
|
||||
nccell_set_fg_rgb8(c, r / blends, g / blends, b / blends);
|
||||
}
|
||||
// UTF-8 encodings of the Braille Patterns are always 0xe2 0xaX 0xCC,
|
||||
// where 0 <= X <= 3 and 0x80 <= CC <= 0xbf (4 groups of 64).
|
||||
char egc[4] = { 0xe2, 0xa0, 0x80, 0x00 };
|
||||
egc[2] += egcidx % 64;
|
||||
egc[1] += egcidx / 64;
|
||||
const char* egc = egcs[egcidx];
|
||||
if(pool_blit_direct(&nc->pool, c, egc, strlen(egc), 1) <= 0){
|
||||
return -1;
|
||||
}
|
||||
@ -1289,6 +926,18 @@ braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
return total;
|
||||
}
|
||||
|
||||
static inline int
|
||||
braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
const blitterargs* bargs){
|
||||
return blit_4x2(nc, linesize, data, leny, lenx, bargs, braille_egcs);
|
||||
}
|
||||
|
||||
static inline int
|
||||
octant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx,
|
||||
const blitterargs* bargs){
|
||||
return blit_4x2(nc, linesize, data, leny, lenx, bargs, octant_egcs);
|
||||
}
|
||||
|
||||
// NCBLIT_DEFAULT is not included, as it has no defined properties. It ought
|
||||
// be replaced with some real blitter implementation by the calling widget.
|
||||
// The order of contents is critical for 'egcs': ncplane_as_rgba() uses these
|
||||
@ -1317,23 +966,23 @@ static struct blitset notcurses_blitters[] = {
|
||||
L"\U0001CD96"
|
||||
L"\U0001CD91"
|
||||
L"\U0001CEA3"
|
||||
L"\U00002582"
|
||||
L"\U00002582"
|
||||
L"\U0001CDCB"
|
||||
L"\U0001CDD3"
|
||||
L"\U0001CDCD"
|
||||
L"\U00002596"
|
||||
L"\U00002596"
|
||||
L"\U0001CDBB"
|
||||
L"\U00002584"
|
||||
L"\U00002584"
|
||||
L"\U0001CDE1"
|
||||
L"\U0001CDDC"
|
||||
L"\U0001CD48"
|
||||
L"\U0001CDBF"
|
||||
L"\U0001CDDE"
|
||||
L"\U00002586"
|
||||
L"\U00002586"
|
||||
L"\U0001CDDF"
|
||||
L"\U0000258C"
|
||||
L"\U0000258C"
|
||||
L"\U0001CDC0"
|
||||
L"\U00002599"
|
||||
L"\U00002599"
|
||||
L"\U0001CDE4"
|
||||
L"\U0001CDE0"),
|
||||
.blit = octant_blit, .name = "oct", .fill = false, },
|
||||
|
Loading…
x
Reference in New Issue
Block a user