diff --git a/src/lib/blit.c b/src/lib/blit.c index 26362dab0..4761fcd98 100644 --- a/src/lib/blit.c +++ b/src/lib/blit.c @@ -508,44 +508,30 @@ quadrant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, return total; } -// Solve for the cell rendered by this 3x2 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 six pixels are different colors). We want to solve for the 2-partition -// of pixels that minimizes total source distance from the resulting lerps. +// Solve for the cell rendered by this cellheightX2 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 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* -sex_solver(const uint32_t rgbas[6], uint64_t* channels, unsigned blendcolors, - unsigned nointerpolate){ - // each element within the set of 64 has an inverse element within the set, - // for which we would calculate the same total differences, so just handle - // the first 32. the partition[] bit masks represent combinations of - // sextants, and their indices correspond to sex[]. - static const char* sex[32] = { - " ", "๐Ÿฌ€", "๐Ÿฌ", "๐Ÿฌƒ", "๐Ÿฌ‡", "๐Ÿฌ", "๐Ÿฌž", "๐Ÿฌ‚", // 0..7 - "๐Ÿฌ„", "๐Ÿฌˆ", "๐Ÿฌ", "๐ŸฌŸ", "๐Ÿฌ…", "๐Ÿฌ‰", "๐Ÿฌ‘", "๐Ÿฌ ", // 8..15 - "๐Ÿฌ‹", "๐Ÿฌ“", "๐Ÿฌข", "๐Ÿฌ–", "๐Ÿฌฆ", "๐Ÿฌญ", "๐Ÿฌ†", "๐ŸฌŠ", // 16..23 - "๐Ÿฌ’", "๐Ÿฌก", "๐ŸฌŒ", "โ–Œ", "๐Ÿฌฃ", "๐Ÿฌ—", "๐Ÿฌง", "๐Ÿฌฎ", // 24..31 - }; - static const unsigned partitions[32] = { - 0, // 1 way to arrange 0 - 1, 2, 4, 8, 16, 32, // 6 ways to arrange 1 - 3, 5, 9, 17, 33, 6, 10, 18, 34, 12, 20, 36, 24, 40, 48, // 15 ways for 2 - // 16 ways to arrange 3, *but* six of them are inverses, so 10 - 7, 11, 19, 35, 13, 21, 37, 25, 41, 49 // 10 + 15 + 6 + 1 == 32 - }; +hires_solver(const uint32_t rgbas[6], uint64_t* channels, unsigned blendcolors, + unsigned nointerpolate, unsigned cellheight, + const char* const* transegcs, const unsigned* partitions){ + const unsigned parcount = 1u << (cellheight * 2 - 1); // 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; //fprintf(stderr, "%06x %06x\n%06x %06x\n%06x %06x\n", rgbas[0], rgbas[1], rgbas[2], rgbas[3], rgbas[4], rgbas[5]); - for(size_t glyph = 0 ; glyph < sizeof(partitions) / sizeof(*partitions) ; ++glyph){ + for(size_t glyph = 0 ; glyph < parcount ; ++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 < 6 ; ++mask){ + for(unsigned mask = 0 ; mask < cellheight * 2 ; ++mask){ if(partitions[glyph] & (1u << mask)){ if(!nointerpolate || !insum){ rsum0 += ncpixel_r(rgbas[mask]); @@ -566,7 +552,7 @@ sex_solver(const uint32_t rgbas[6], uint64_t* channels, unsigned blendcolors, uint32_t l1 = generalerp(rsum1, gsum1, bsum1, outsum); //fprintf(stderr, "sum0: %06x sum1: %06x insum: %d\n", l0 & 0xffffffu, l1 & 0xffffffu, insum); uint32_t totaldiff = 0; - for(unsigned mask = 0 ; mask < 6 ; ++mask){ + for(unsigned mask = 0 ; mask < cellheight * 2 ; ++mask){ unsigned r, g, b; if(partitions[glyph] & (1u << mask)){ ncchannel_rgb8(l0, &r, &g, &b); @@ -590,38 +576,307 @@ sex_solver(const uint32_t rgbas[6], uint64_t* channels, unsigned blendcolors, } } //fprintf(stderr, "solved for best: %d (%u)\n", best, mindiff); - assert(best >= 0 && best < 32); if(blendcolors){ ncchannels_set_fg_alpha(channels, NCALPHA_BLEND); ncchannels_set_bg_alpha(channels, NCALPHA_BLEND); } - return sex[best]; + best = parcount * 2 - 1 - partitions[best]; + assert(best >= 0 && best >= (1u << (cellheight * 2 - 1)) && best < (1u << (cellheight * 2))); + return transegcs[best]; } +// FIXME replace both of these arrays of pointers with fixed-width matrices +// bit of index is *set* where sextant *is not* +// 32: bottom right 16: bottom left +// 8: middle right 4: middle left +// 2: upper right 1: upper left +static const char* const sextrans[64] = { + "โ–ˆ", "๐Ÿฌป", "๐Ÿฌบ", "๐Ÿฌน", "๐Ÿฌธ", "๐Ÿฌท", "๐Ÿฌถ", "๐Ÿฌต", + "๐Ÿฌด", "๐Ÿฌณ", "๐Ÿฌฒ", "๐Ÿฌฑ", "๐Ÿฌฐ", "๐Ÿฌฏ", "๐Ÿฌฎ", "๐Ÿฌญ", + "๐Ÿฌฌ", "๐Ÿฌซ", "๐Ÿฌช", "๐Ÿฌฉ", "๐Ÿฌจ", "โ–", "๐Ÿฌง", "๐Ÿฌฆ", + "๐Ÿฌฅ", "๐Ÿฌค", "๐Ÿฌฃ", "๐Ÿฌข", "๐Ÿฌก", "๐Ÿฌ ", "๐ŸฌŸ", "๐Ÿฌž", + "๐Ÿฌ", "๐Ÿฌœ", "๐Ÿฌ›", "๐Ÿฌš", "๐Ÿฌ™", "๐Ÿฌ˜", "๐Ÿฌ—", "๐Ÿฌ–", + "๐Ÿฌ•", "๐Ÿฌ”", "โ–Œ", "๐Ÿฌ“", "๐Ÿฌ’", "๐Ÿฌ‘", "๐Ÿฌ", "๐Ÿฌ", + "๐ŸฌŽ", "๐Ÿฌ", "๐ŸฌŒ", "๐Ÿฌ‹", "๐ŸฌŠ", "๐Ÿฌ‰", "๐Ÿฌˆ", "๐Ÿฌ‡", + "๐Ÿฌ†", "๐Ÿฌ…", "๐Ÿฌ„", "๐Ÿฌƒ", "๐Ÿฌ‚", "๐Ÿฌ", "๐Ÿฌ€", " ", +}; + +// bit of index is *set* where octant *is not* +// 1: row 0 left 2: row 0 right +// 4: row 1 left 8: row 1 right +// 16: row 2 left 32: row 2 right +// 64: row 3 left 128: row 3 right +static const char* const octtrans[256] = { + u8"\U00002588", // โ–ˆ 255 all eight set (full) + u8"\U0001cde5", // ๐œทฅ 254 missing upper left (o2345678) + u8"\U0001cde4", // ๐œทค 253 missing upper right (o1345678) + u8"\U00002586", // โ–† 252 missing row 0 (lower three quarters) + u8"\U0001cde3", // ๐œทฃ 251 missing row 1 left (o1245678) + u8"\U0000259f", // โ–Ÿ 250 (q upper right and lower left and lower right) + u8"\U0001cde2", // ๐œทข 249 (o1245678) + u8"\U0001cde1", // ๐œทก 248 (o45678) + u8"\U0001cde0", // ๐œท  247 missing row 1 right (o1235678) + u8"\U0001cddf", // ๐œทŸ 246 missing 0 left 1 right (o235678) + u8"\U00002599", // โ–™ 245 missing 0/1 right (q upper left and lower left and lower right) + u8"\U0001cdde", // ๐œทž 244 + u8"\U0001cddd", // ๐œท 243 + u8"\U0001cddc", // ๐œทœ 242 + u8"\U0001cddb", // ๐œท› 241 (o15678) + u8"\U00002584", // โ–„ 240 2/3 full (lower half) + u8"\U0001cdda", // ๐œทš 239 (o1234678) + u8"\U0001cdd9", // ๐œท™ 238 (o234678) + u8"\U0001cdd8", // ๐œท˜ 237 (o134678) + u8"\U0001cdd7", // ๐œท— 236 (o34678) + u8"\U0001cdd6", // ๐œท– 235 (o124678) + u8"\U0001cdd5", // ๐œท• 234 (o24678) + u8"\U0001cdd4", // ๐œท” 233 (o14678) + u8"\U0001cdd3", // ๐œท“ 232 (o4678) + u8"\U0001cdd2", // ๐œท’ 231 + u8"\U0001cdd1", // ๐œท‘ 230 + u8"\U0001cdd0", // ๐œท 229 + u8"\U0001cdcf", // ๐œท 228 (o145678) + u8"\U0001cdce", // ๐œทŽ 227 + u8"\U0001cdcd", // ๐œท 226 + u8"\U0001cdcc", // ๐œทŒ 225 + u8"\U0001cdcb", // ๐œท‹ 224 (o678) + u8"\U0001cdca", + u8"\U0001cdc9", + u8"\U0001cdc8", + u8"\U0001cdc7", // ๐œท‡ 220 (o34578) + u8"\U0001cdc6", + u8"\U0001cdc5", + u8"\U0001cdc4", + u8"\U0001cdc3", // ๐œทƒ 216 (o4578) + u8"\U0001cdc2", + u8"\U0001cdc1", + u8"\U0001cdc0", + u8"\U0001cdbf", // ๐œถฟ 212 (o3578) + u8"\U0001cdbe", + u8"\U0001cdbd", + u8"\U0001cdbc", + u8"\U0001cdbb", // ๐œถป 208 (o578) + u8"\U0001cdba", + u8"\U0001cdb9", + u8"\U0001cdb8", + u8"\U0001cdb7", // ๐œถท 204 (o4578) + u8"\U0001cdb6", + u8"\U0001cdb5", + u8"\U0001cdb4", + u8"\U0001cdb3", // ๐œถณ 200 (o478) + u8"\U0001cdb2", + u8"\U0001cdb1", + u8"\U0001cdb0", + u8"\U0001cdaf", // ๐œถฏ 196 (o378) + u8"\U0001cdae", + u8"\U0001cdad", + u8"\U0001cdac", + u8"\U00002582", // โ–‚ 192 (lower one quarter) + u8"\U0001cdab", + u8"\U0001cdaa", + u8"\U0001cda9", + u8"\U0001cda8", // ๐œถจ 188 (o34568) + u8"\U0001cda7", + u8"\U0001cda6", + u8"\U0001cda5", + u8"\U0001cda4", + u8"\U0001cda3", + u8"\U0001cda2", + u8"\U0001cda1", + u8"\U0001cda0", + u8"\U0001cd9f", + u8"\U0001cd9e", + u8"\U0001cd9d", + u8"\U0001cd9c", + u8"\U0000259c", // โ–œ 175 (q upper left and upper right and lower right) + u8"\U0001cd9b", + u8"\U0001cd9a", + u8"\U0001cd99", + u8"\U0001cd98", + u8"\U00002590", // โ– 170 (right half) + u8"\U0001cd97", + u8"\U0001cd96", + u8"\U0001cd95", + u8"\U0001cd94", + u8"\U0000259a", // โ–š 165 (q upper left and lower right) + u8"\U0001cd93", + u8"\U0001cd92", + u8"\U0001cd91", + u8"\U0001cd90", + u8"\U00002597", // โ–— 160 (q lower right) + u8"\U0001cd8f", + u8"\U0001cd8e", + u8"\U0001cd8d", + u8"\U0001cd8c", // ๐œถŒ 156 (u3458) + u8"\U0001cd8b", + u8"\U0001cd8a", + u8"\U0001cd89", + u8"\U0001cd88", // ๐œถˆ 152 (u458) + u8"\U0001cd87", + u8"\U0001cd86", + u8"\U0001cd85", + u8"\U0001cd84", // ๐œถ„ 148 (u358) + u8"\U0001cd83", + u8"\U0001cd82", + u8"\U0001cd81", + u8"\U0001cd80", // ๐œถ€ 144 (u58) + u8"\U0001cd7f", + u8"\U0001cd7e", + u8"\U0001cd7d", + u8"\U0001cd7c", // ๐œตผ 140 (u348) + u8"\U0001cd7b", + u8"\U0001cd7a", + u8"\U0001cd79", + u8"\U0001cd78", // ๐œตธ 136 (u48) + u8"\U0001cd77", + u8"\U0001cd76", + u8"\U0001cd75", + u8"\U0001cd74", // ๐œตด 132 (u38) + u8"\U0001cd73", + u8"\U0001cd72", + u8"\U0001cd71", + u8"\U0001cea0", // ๐œบ  128 lower right only (right half lower one quarter) + u8"\U0001cd70", // ๐œตฐ 127 missing lower right (u1234567) + u8"\U0001cd6f", + u8"\U0001cd6e", + u8"\U0001cd6d", + u8"\U0001cd6c", + u8"\U0001cd6b", + u8"\U0001cd6a", + u8"\U0001cd69", + u8"\U0001cd68", + u8"\U0001cd67", + u8"\U0001cd66", + u8"\U0001cd65", + u8"\U0001cd64", + u8"\U0001cd63", + u8"\U0001cd62", + u8"\U0001cd61", + u8"\U0001cd60", + u8"\U0001cd5f", + u8"\U0001cd5e", + u8"\U0001cd5d", + u8"\U0001cd5c", + u8"\U0001cd5b", + u8"\U0001cd5a", + u8"\U0001cd59", + u8"\U0001cd58", + u8"\U0001cd57", + u8"\U0001cd56", + u8"\U0001cd55", + u8"\U0001cd54", + u8"\U0001cd53", + u8"\U0001cd52", + u8"\U0001cd51", + u8"\U0000259b", // โ–› 95 0/1 full 2/3 left (q upper left and upper right and lower left) + u8"\U0001cd50", + u8"\U0001cd4f", + u8"\U0001cd4e", + u8"\U0001cd4d", + u8"\U0000259e", // โ–ž 92 0/1 right 2/3 left (q upper right and lower left) + u8"\U0001cd4c", + u8"\U0001cd4b", + u8"\U0001cd4a", + u8"\U0001cd49", + u8"\U0000258c", // โ–Œ 85 0/1/2/3 left (left block) + u8"\U0001cd48", + u8"\U0001cd47", + u8"\U0001cd46", + u8"\U0001cd45", + u8"\U00002596", // โ–– 80 2/3 left (q lower left) + u8"\U0001cd44", + u8"\U0001cd43", + u8"\U0001cd42", + u8"\U0001cd41", + u8"\U0001cd40", + u8"\U0001cd3f", + u8"\U0001cd3e", + u8"\U0001cd3d", + u8"\U0001cd3c", + u8"\U0001cd3b", + u8"\U0001cd3a", + u8"\U0001cd39", + u8"\U0001cd38", + u8"\U0001cd37", // ๐œดท 66 0 right 3 left (o27) + u8"\U0001cd36", // ๐œดถ 65 0 left 3 left (o17) + u8"\U0001cea3", // ๐œบฃ 64 lower left only (left half lower one quarter) + u8"\U0001fb85", // ๐Ÿฎ… 63 row 0/1/2 full (upper three quarters) + u8"\U0001cd35", // ๐œดต 62 (o23456) + u8"\U0001cd34", // ๐œดด 61 (o13456) + u8"\U0001cd33", // ๐œดณ 60 (o3456) + u8"\U0001cd32", // ๐œดฒ 59 (o12456) + u8"\U0001cd31", // ๐œดฑ 58 (o2456) + u8"\U0001cd30", // ๐œดฐ 57 0 left 1 right 2 full (o1456) + u8"\U0001cd2f", // ๐œดฏ 56 (o456) + u8"\U0001cd2e", // ๐œดฎ 55 + u8"\U0001cd2d", // ๐œดญ 54 + u8"\U0001cd2c", // ๐œดฌ 53 + u8"\U0001cd2b", // ๐œดซ 52 + u8"\U0001cd2a", // ๐œดช 51 + u8"\U0001cd29", // ๐œดฉ 50 + u8"\U0001cd28", // ๐œดจ 49 + u8"\U0001cd27", // ๐œดง 48 + u8"\U0001cd26", // ๐œดฆ 47 (o12346) + u8"\U0001cd25", // ๐œดฅ 46 (o2346) + u8"\U0001cd24", // ๐œดค 45 (o1346) + u8"\U0001cd23", // ๐œดฃ 44 (o346) + u8"\U0001cd22", // ๐œดข 43 (o1246) + u8"\U0001cd21", // ๐œดก 42 (o246) + u8"\U0001cd20", // ๐œด  41 (o146) + u8"\U0001fbe7", // ๐Ÿฏง 40 (middle right one quarter) + u8"\U0001cd1f", // ๐œดŸ 39 (o1236) + u8"\U0001cd1e", // ๐œดž 38 (o236) + u8"\U0001cd1d", // ๐œด 37 (o136) + u8"\U0001cd1c", // ๐œดœ 36 (o36) + u8"\U0001cd1b", // ๐œด› 35 (o126) + u8"\U0001cd1a", // ๐œดš 34 (o26) + u8"\U0001cd19", // ๐œด™ 33 (o16) + u8"\U0001cd18", // ๐œด˜ 32 row 2 right only (o6) + u8"\U0001cd17", // ๐œด— 31 (o12345) + u8"\U0001cd16", // ๐œด– 30 (o2345) + u8"\U0001cd15", // ๐œด• 29 (o1345) + u8"\U0001cd14", // ๐œด” 28 (o345) + u8"\U0001cd13", // ๐œด“ 27 (o1245) + u8"\U0001cd12", // ๐œด’ 26 row 0/1 right row 2 l (o245) + u8"\U0001cd11", // ๐œด‘ 25 row 1/2 left row 1 r (o145) + u8"\U0001cd10", // ๐œด 24 row 1 right row 2 left (o45) + u8"\U0001cd0f", // ๐œด 23 row 0 full row 1/2 l (o1235) + u8"\U0001cd0e", // ๐œดŽ 22 row 1 right row 2/3 l (o235) + u8"\U0001cd0d", // ๐œด 21 row 0/1/2 left (o135) + u8"\U0001fbe6", // ๐Ÿฏฆ 20 row 1/2 left (middle left one quarter) + u8"\U0001cd0c", // ๐œดŒ 19 row 0 full row 2 left (o125) + u8"\U0001cd0b", // ๐œด‹ 18 row 0 right row 2 left (o25) + u8"\U0001cd0a", // ๐œดŠ 17 row 0 left row 2 left (o15) + u8"\U0001cd09", // ๐œด‰ 16 row 2 left only (o5) + u8"\U00002580", // โ–€ 15 row 0/1 full (upper half) + u8"\U0001cd08", // ๐œดˆ 14 row 0 right row 1 full (o234) + u8"\U0001cd07", // ๐œด‡ 13 row 0 left row 1 full (o134) + u8"\U0001cd06", // ๐œด† 12 row 1 full (o34) + u8"\U0001cd05", // ๐œด… 11 row 0 full row 1 right (o124) + u8"\U0000259d", // โ– 10 row 0/1 right only (upper right quadrant) + u8"\U0001cd04", // ๐œด„ 9 row 0 left row 1 right (o14) + u8"\U0001cd03", // ๐œดƒ 8 row 1 right only (o4) + u8"\U0001cd02", // ๐œด‚ 7 row 0 full row 1 left (o123) + u8"\U0001cd01", // ๐œด 6 row 0 right row 1 left (o23) + u8"\U00002598", // โ–˜ 5 row 0/1 left only (upper left quadrant) + u8"\U0001cd00", // ๐œด€ 4 row 1 left only (o3) + u8"\U0001fb82", // ๐Ÿฎ‚ 3 row 0 (upper one quarter) + u8"\U0001ceab", // ๐œบซ 2 upper right only (right half upper one quarter) + u8"\U0001cea8", // ๐œบจ 1 upper left only (left half upper one quarter) + u8" " // 0 none set (space) +}; + static const char* -sex_trans_check(nccell* c, const uint32_t rgbas[6], unsigned blendcolors, - uint32_t transcolor, unsigned nointerpolate){ - // bit is *set* where sextant *is not* - // 32: bottom right 16: bottom left - // 8: middle right 4: middle left - // 2: upper right 1: upper left - static const char* sex[64] = { - "โ–ˆ", "๐Ÿฌป", "๐Ÿฌบ", "๐Ÿฌน", "๐Ÿฌธ", "๐Ÿฌท", "๐Ÿฌถ", "๐Ÿฌต", - "๐Ÿฌด", "๐Ÿฌณ", "๐Ÿฌฒ", "๐Ÿฌฑ", "๐Ÿฌฐ", "๐Ÿฌฏ", "๐Ÿฌฎ", "๐Ÿฌญ", - "๐Ÿฌฌ", "๐Ÿฌซ", "๐Ÿฌช", "๐Ÿฌฉ", "๐Ÿฌจ", "โ–", "๐Ÿฌง", "๐Ÿฌฆ", - "๐Ÿฌฅ", "๐Ÿฌค", "๐Ÿฌฃ", "๐Ÿฌข", "๐Ÿฌก", "๐Ÿฌ ", "๐ŸฌŸ", "๐Ÿฌž", - "๐Ÿฌ", "๐Ÿฌœ", "๐Ÿฌ›", "๐Ÿฌš", "๐Ÿฌ™", "๐Ÿฌ˜", "๐Ÿฌ—", "๐Ÿฌ–", - "๐Ÿฌ•", "๐Ÿฌ”", "โ–Œ", "๐Ÿฌ“", "๐Ÿฌ’", "๐Ÿฌ‘", "๐Ÿฌ", "๐Ÿฌ", - "๐ŸฌŽ", "๐Ÿฌ", "๐ŸฌŒ", "๐Ÿฌ‹", "๐ŸฌŠ", "๐Ÿฌ‰", "๐Ÿฌˆ", "๐Ÿฌ‡", - "๐Ÿฌ†", "๐Ÿฌ…", "๐Ÿฌ„", "๐Ÿฌƒ", "๐Ÿฌ‚", "๐Ÿฌ", "๐Ÿฌ€", " ", - }; +hires_trans_check(nccell* c, const uint32_t* rgbas, unsigned blendcolors, + uint32_t transcolor, unsigned nointerpolate, int cellheight, + const char* const* transegcs){ unsigned transstring = 0; unsigned r = 0, g = 0, b = 0; unsigned div = 0; - for(unsigned mask = 0 ; mask < 6 ; ++mask){ + // check each pixel for transparency + for(int mask = 0 ; mask < cellheight * 2 ; ++mask){ if(rgba_trans_p(rgbas[mask], transcolor)){ transstring |= (1u << mask); - }else if(!nointerpolate || !div){ + }else if(!nointerpolate || !div){ // force an initialization if nointerpolate r += ncpixel_r(rgbas[mask]); g += ncpixel_g(rgbas[mask]); b += ncpixel_b(rgbas[mask]); @@ -633,8 +888,9 @@ sex_trans_check(nccell* c, const uint32_t rgbas[6], unsigned blendcolors, } 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 = sex[transstring]; + // is just a general lerp across non-transparent pixels. transstring can only + // have 0x80 and/or 0x40 set if cellheight was 4. + const char* egc = transegcs[transstring]; nccell_set_bg_alpha(c, NCALPHA_TRANSPARENT); //fprintf(stderr, "transtring: %u egc: %s\n", transtring, egc); if(*egc == ' '){ // entirely transparent @@ -646,58 +902,69 @@ sex_trans_check(nccell* c, const uint32_t rgbas[6], unsigned blendcolors, if(blendcolors){ nccell_set_fg_alpha(c, NCALPHA_BLEND); } - cell_set_blitquadrants(c, !(transstring & 5u), !(transstring & 10u), - !(transstring & 20u), !(transstring & 40u)); + if(cellheight == 3){ + cell_set_blitquadrants(c, !(transstring & 0x5), !(transstring & 0xa), + !(transstring & 0x14), !(transstring & 0x28)); + }else{ + cell_set_blitquadrants(c, !(transstring & 0x5), !(transstring & 0xa), + !(transstring & 0x50), !(transstring & 0xa0)); + } } //fprintf(stderr, "SEX-BQ: 0x%x\n", cell_blittedquadrants(c)); return egc; } -// sextant blitter. maps 3x2 to each cell. since we only have two colors at -// our disposal (foreground and background), we lose some fidelity. +// sextant/octant blitter. maps 3x2 or 4x2 to each cell. since we only have two +// colors at our disposal (foreground and background), we generally lose some +// color fidelity. static inline int -sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, - const blitterargs* bargs){ +hires_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, + const blitterargs* bargs, int cellheight, + const char* const* transegcs, const unsigned* partitions){ 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, "sexblitter %dx%d -> %d/%d+%d/%d\n", leny, lenx, dimy, dimx, bargs->u.cell.placey, bargs->u.cell.placex); +//fprintf(stderr, "hiresblitter %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 += 3){ + assert(cellheight <= 4); // due to rgbas[] array below + for(y = bargs->u.cell.placey ; visy < (bargs->begy + leny) && y < dimy ; ++y, visy += cellheight){ 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[6] = { 0, 0, 0, 0, 0, 0 }; + uint32_t rgbas[8]; // row-major + memset(rgbas, 0, sizeof(rgbas)); memcpy(&rgbas[0], (dat + (linesize * visy) + (visx * 4)), sizeof(*rgbas)); + // conditional looks at first column, begininng at the second row + for(int yoff = 1 ; yoff < cellheight ; ++yoff){ + if(visy < bargs->begy + leny - yoff){ + memcpy(&rgbas[yoff * 2], (dat + (linesize * (visy + yoff)) + (visx * 4)), sizeof(*rgbas)); + } + } + // conditional looks at second column, beginning at second row 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)); + for(int yoff = 1 ; yoff < cellheight ; ++yoff){ + if(visy < bargs->begy + leny - yoff){ + memcpy(&rgbas[1 + yoff * 2], (dat + (linesize * (visy + yoff)) + ((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)); - } - } nccell* c = ncplane_cell_ref_yx(nc, y, x); c->channels = 0; c->stylemask = 0; - const char* egc = sex_trans_check(c, rgbas, blendcolors, bargs->transcolor, nointerpolate); + const char* egc = hires_trans_check(c, rgbas, blendcolors, bargs->transcolor, + nointerpolate, cellheight, transegcs); if(egc == NULL){ // no transparency; run a full solver - egc = sex_solver(rgbas, &c->channels, blendcolors, nointerpolate); + egc = hires_solver(rgbas, &c->channels, blendcolors, nointerpolate, + cellheight, transegcs, partitions); cell_set_blitquadrants(c, 1, 1, 1, 1); } -//fprintf(stderr, "sex EGC: %s channels: %016lx\n", egc, c->channels); +//fprintf(stderr, "hires EGC: %s channels: %016lx\n", egc, c->channels); if(*egc){ if(pool_blit_direct(&nc->pool, c, egc, strlen(egc), 1) <= 0){ return -1; @@ -711,46 +978,78 @@ sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, return total; } -// Bit is set where octant is present: -// 0 1 -// 2 3 -// 4 5 -// 6 7 -// 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", -}; +static inline int +sextant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, + const blitterargs* bargs){ + // each element within the set of 64 has an inverse element within the set, + // for which we would calculate the same total differences, so just handle + // the first 32. the sextition[] bit masks represent combinations of + // sextants, and their indices correspond to inverse sextrans[]. + static const unsigned sextitions[32] = { + 0, // 1 way to arrange 0 + 1, 2, 4, 8, 16, 32, // 6 ways to arrange 1 + 3, 5, 9, 17, 33, 6, 10, 18, 34, 12, 20, 36, 24, 40, 48, // 15 ways for 2 + // 16 ways to arrange 3, *but* six of them are inverses, so 10 + 7, 11, 19, 35, 13, 21, 37, 25, 41, 49 // 10 + 15 + 6 + 1 == 32 + }; + return hires_blit(nc, linesize, data, leny, lenx, bargs, 3, sextrans, sextitions); +} + +static inline int +octant_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, + const blitterargs* bargs){ + // 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. the octition[] bit masks represent combinations of + // octants, and their indices correspond to inverse octtrans[]. +#define E(bits) (1u << (bits)) + static const unsigned octitions[128] = { + 0, + // one set + E(0), E(1), E(2), E(3), E(4), E(5), E(6), E(7), + // two set (7 + 6 + 5 + 4 + 3 + 2 + 1 = 28) + E(0) + E(1), E(0) + E(2), E(0) + E(3), E(0) + E(4), E(0) + E(5), E(0) + E(6), E(0) + E(7), + E(1) + E(2), E(1) + E(3), E(1) + E(4), E(1) + E(5), E(1) + E(6), E(1) + E(7), + E(2) + E(3), E(2) + E(4), E(2) + E(5), E(2) + E(6), E(2) + E(7), + E(3) + E(4), E(3) + E(5), E(3) + E(6), E(3) + E(7), + E(4) + E(5), E(4) + E(6), E(4) + E(7), + E(5) + E(6), E(5) + E(7), + E(6) + E(7), + // three set (21 + 15 + 10 + 6 + 3 + 1 = 56) + E(0) + E(1) + E(2), E(0) + E(1) + E(3), E(0) + E(1) + E(4), E(0) + E(1) + E(5), + E(0) + E(1) + E(6), E(0) + E(1) + E(7), E(0) + E(2) + E(3), E(0) + E(2) + E(4), + E(0) + E(2) + E(5), E(0) + E(2) + E(6), E(0) + E(2) + E(7), E(0) + E(3) + E(4), + E(0) + E(3) + E(5), E(0) + E(3) + E(6), E(0) + E(3) + E(7), E(0) + E(4) + E(5), + E(0) + E(4) + E(6), E(0) + E(4) + E(7), E(0) + E(5) + E(6), E(0) + E(5) + E(7), + E(0) + E(6) + E(7), // 0 + 6 + 7 + E(1) + E(2) + E(3), E(1) + E(2) + E(4), E(1) + E(2) + E(5), E(1) + E(2) + E(6), + E(1) + E(2) + E(7), E(1) + E(3) + E(4), E(1) + E(3) + E(5), E(1) + E(3) + E(6), + E(1) + E(3) + E(7), E(1) + E(4) + E(5), E(1) + E(4) + E(6), E(1) + E(4) + E(7), + E(1) + E(5) + E(6), E(1) + E(5) + E(7), E(1) + E(6) + E(7), + E(2) + E(3) + E(4), E(2) + E(3) + E(5), E(2) + E(3) + E(6), E(2) + E(3) + E(7), + E(2) + E(4) + E(5), E(2) + E(4) + E(6), E(2) + E(4) + E(7), E(2) + E(5) + E(6), + E(2) + E(5) + E(7), E(2) + E(6) + E(7), + E(3) + E(4) + E(5), E(3) + E(4) + E(6), E(3) + E(4) + E(7), E(3) + E(5) + E(6), + E(3) + E(5) + E(7), E(3) + E(6) + E(7), + E(4) + E(5) + E(6), E(4) + E(5) + E(7), E(4) + E(6) + E(7), + E(5) + E(6) + E(7), + // four set (15 + 10 + 6 + 3 + 1 = 35) + E(0) + E(1) + E(2) + E(3), E(0) + E(1) + E(2) + E(4), E(0) + E(1) + E(2) + E(5), + E(0) + E(1) + E(2) + E(6), E(0) + E(1) + E(2) + E(7), E(0) + E(1) + E(3) + E(4), + E(0) + E(1) + E(3) + E(5), E(0) + E(1) + E(3) + E(6), E(0) + E(1) + E(3) + E(7), + E(0) + E(1) + E(4) + E(5), E(0) + E(1) + E(4) + E(6), E(0) + E(1) + E(4) + E(7), + E(0) + E(1) + E(5) + E(6), E(0) + E(1) + E(5) + E(7), E(0) + E(1) + E(6) + E(7), + E(0) + E(2) + E(3) + E(4), E(0) + E(2) + E(3) + E(5), E(0) + E(2) + E(3) + E(6), + E(0) + E(2) + E(3) + E(7), E(0) + E(2) + E(4) + E(5), E(0) + E(2) + E(4) + E(6), + E(0) + E(2) + E(4) + E(7), E(0) + E(2) + E(5) + E(6), E(0) + E(2) + E(5) + E(7), + E(0) + E(2) + E(6) + E(7), E(0) + E(3) + E(4) + E(5), E(0) + E(3) + E(4) + E(6), + E(0) + E(3) + E(4) + E(7), E(0) + E(3) + E(5) + E(6), E(0) + E(3) + E(5) + E(7), + E(0) + E(3) + E(6) + E(7), E(0) + E(4) + E(5) + E(6), E(0) + E(4) + E(5) + E(7), + E(0) + E(4) + E(6) + E(7), E(0) + E(5) + E(6) + E(7), +#undef E + }; + return hires_blit(nc, linesize, data, leny, lenx, bargs, 4, octtrans, octitions); +} // Bit is set where Braille dot is present: // 0 1 @@ -804,14 +1103,10 @@ fold_rgb8(unsigned* restrict r, unsigned* restrict g, unsigned* restrict b, ++*foldcount; } -// 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. +// Braille maps 4x2 to each cell, always using a transparent background. static inline int -blit_4x2(ncplane* nc, int linesize, const void* data, int leny, int lenx, - const blitterargs* bargs, const char egcs[256][5]){ +braille_blit(ncplane* nc, int linesize, const void* data, int leny, int lenx, + const blitterargs* bargs){ const bool blendcolors = bargs->flags & NCVISUAL_OPTION_BLEND; unsigned dimy, dimx, x, y; int total = 0; // number of cells written @@ -915,7 +1210,7 @@ blit_4x2(ncplane* nc, int linesize, const void* data, int leny, int lenx, if(blends){ nccell_set_fg_rgb8(c, r / blends, g / blends, b / blends); } - const char* egc = egcs[egcidx]; + const char* egc = braille_egcs[egcidx]; if(pool_blit_direct(&nc->pool, c, egc, strlen(egc), 1) <= 0){ return -1; } @@ -926,18 +1221,6 @@ blit_4x2(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