Advertisement
Guest User

Untitled

a guest
Aug 2nd, 2020
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.77 KB | None | 0 0
  1. // bpc.cpp : Defines the entry point for the console application.
  2. //
  3.  
  4. #include <cstdio>
  5. #include <cstdint>
  6. #include <vector>
  7. #include <locale>
  8.  
  9. #define IMSIZE (128*128)
  10.  
  11. // BPE compression
  12.  
  13. //The number of actual valid symbols. 16 here to encode the 16 Pico8 colours
  14. #define SYMBOLS 16
  15. //How many pairs can be defined. I chose this and ASCOFF to fit easily into plain ASCII
  16. #define PAIRS 73
  17. #define TOTALCODES (SYMBOLS+PAIRS)
  18. #define ASCOFF 35
  19.  
  20. uint8_t left[PAIRS];
  21. uint8_t right[PAIRS];
  22. uint32_t counts[TOTALCODES*TOTALCODES];
  23. uint32_t numpairs;
  24.  
  25. uint8_t palette[16][3] =
  26. {
  27.     { 0, 0, 0 }     ,
  28.     { 29, 43, 83 }  ,
  29.     {126, 37, 83}   ,
  30.     {0, 135, 81}    ,
  31.     {171, 82, 54}   ,
  32.     {95, 87, 79 }   ,
  33.     {194, 195, 199} ,
  34.     {255, 241, 232} ,
  35.     {255, 0, 77}    ,
  36.     {255, 163, 0}   ,
  37.     {255, 236, 39}  ,
  38.     {0, 228, 54}    ,
  39.     {41, 173, 255}  ,
  40.     {131, 118, 156} ,
  41.     {255, 119, 168} ,
  42.     {255, 204, 170}
  43. };
  44.  
  45. //Read one line of PPM header, throwing away comments
  46. void GetLine(FILE* file)
  47. {
  48.     char temp[1000];
  49.  
  50.     do
  51.     {
  52.         fgets(temp, 1000, file);
  53.     } while (temp[0] == '#');
  54. }
  55.  
  56. //Convert to PICO8 pallete. Just aborts if it finds a colour not in there.
  57.  
  58. uint8_t MapCol(uint8_t r, uint8_t g, uint8_t b)
  59. {
  60.     for (uint8_t i = 0; i < 16; i++)
  61.     {
  62.         if ((r == palette[i][0]) && (g == palette[i][1]) && (b == palette[i][2]))
  63.         {
  64.             return i;
  65.         }
  66.     }
  67.  
  68.     printf("ERROR: COLOUR NOT FOUND\n");
  69.     exit(-1);
  70.  
  71.     return 0;
  72. }
  73.  
  74. //Tweak backslashes so they don't get escaped. Does [[ ]] strings avoid the need to do this?
  75.  
  76. uint8_t NoEscape(uint8_t i )
  77. {
  78.     if (i == 92) return 126;
  79.     return i;
  80. }
  81.  
  82. bool OnePass(const std::vector<uint8_t>& input, std::vector<uint8_t>& output)
  83. {
  84.     if (numpairs == PAIRS)
  85.     {
  86.         output = input;
  87.         return false;
  88.     }
  89.  
  90.     // find the most common pair
  91.     std::fill(counts, counts + TOTALCODES*TOTALCODES, 0);
  92.     output.clear();
  93.  
  94.     for (uint32_t i = 0; i < input.size() - 1; i++)
  95.     {
  96.         counts[((uint32_t)input[i])*TOTALCODES + input[i + 1]]++;
  97.     }
  98.  
  99.     uint32_t max=0;
  100.     uint32_t maxpair=0;
  101.  
  102.     for (uint32_t i = 0; i < TOTALCODES*TOTALCODES; i++)
  103.     {
  104.         if (counts[i]>max)
  105.         {
  106.             max = counts[i];
  107.             maxpair = i;
  108.         }
  109.     }
  110.  
  111.     // transform the input using this.
  112.  
  113.     uint32_t thisleft = maxpair / TOTALCODES;
  114.     uint32_t thisright = maxpair % TOTALCODES;
  115.  
  116.     left[numpairs] = thisleft;
  117.     right[numpairs] = thisright;
  118.     numpairs++;
  119.  
  120.     uint32_t i = 0;
  121.  
  122.     while (i < input.size())
  123.     {
  124.         if (i == (input.size() - 1))
  125.         {
  126.             output.push_back(input[i]);
  127.             i++;
  128.         }
  129.         else
  130.         {
  131.             if ((input[i] == thisleft) && (input[i + 1] == thisright))
  132.             {
  133.                 output.push_back(numpairs - 1 + SYMBOLS);
  134.                 i += 2;
  135.             }
  136.             else
  137.             {
  138.                 output.push_back(input[i]);
  139.                 i++;
  140.             }
  141.         }
  142.     }
  143.  
  144.     return true;
  145. }
  146.  
  147. void Compress(const std::vector<uint8_t>& input, std::vector<uint8_t>& output)
  148. {
  149.     numpairs = 0;
  150.     std::fill(left, left + PAIRS, 0);
  151.     std::fill(right, right + PAIRS, 0);
  152.     std::vector<uint8_t> temp = input;
  153.  
  154.     // do repeated passes until we can encode no more pairs
  155.     while (OnePass(temp, output))
  156.     {
  157.         std::swap(temp, output);
  158.     }
  159.  
  160.     return;
  161. }
  162.  
  163. // define this to do a decompression and verify pass
  164. #if VERIFY
  165.  
  166. void AddSymbol(uint8_t c, std::vector<uint8_t>& output)
  167. {
  168.     if (c >= SYMBOLS)
  169.     {
  170.         AddSymbol(left[c - SYMBOLS], output);
  171.         AddSymbol(right[c - SYMBOLS], output);
  172.     }
  173.     else
  174.     {
  175.         output.push_back(c);
  176.     }
  177. }
  178.  
  179.  
  180. void Decompress(const std::vector<uint8_t>& input, std::vector<uint8_t>& output)
  181. {
  182.     for (uint32_t i = 0; i < input.size(); i++)
  183.     {
  184.         AddSymbol(input[i], output);
  185.     }
  186. }
  187.  
  188. #endif
  189.  
  190. //main entry point
  191.  
  192. int main(int argc, char* argv[])
  193. {
  194.     if (argc != 2)
  195.     {
  196.         printf("USAGE: bpc filename.ppm\n");
  197.         return -1;
  198.     }
  199.  
  200.     FILE* file = fopen(argv[1], "rb");
  201.  
  202.     std::vector<uint8_t> input, compressed, decompressed;
  203.  
  204.     input.resize(IMSIZE);
  205.  
  206.     if (file)
  207.     {
  208.         GetLine(file);
  209.         GetLine(file);
  210.         GetLine(file);
  211.  
  212.         for (int i = 0; i < IMSIZE; i++)
  213.         {
  214.             uint8_t r = fgetc(file);
  215.             uint8_t g = fgetc(file);
  216.             uint8_t b = fgetc(file);
  217.  
  218.             input[i] = MapCol(r,g,b);
  219.         }
  220.  
  221.         Compress(input, compressed);
  222.  
  223. #if VERIFY
  224.        
  225.         Decompress(compressed, decompressed);
  226.  
  227.         for (uint32_t i = 0; i < IMSIZE; i++)
  228.         {
  229.             if (input[i] != decompressed[i])
  230.             {
  231.                 printf("MISMATCH ERROR %i %i %i\n", i, input[i], decompressed[i]);
  232.             }
  233.         }
  234.  
  235. #endif
  236.  
  237.         printf("left=\"");
  238.  
  239.         for (uint32_t i = 0; i < PAIRS; i++)
  240.         {
  241.             putchar(NoEscape(left[i] + ASCOFF));
  242.         }
  243.         printf("\"\nright=\"");
  244.  
  245.         for (uint32_t i = 0; i < PAIRS; i++)
  246.         {
  247.             putchar(NoEscape(right[i] + ASCOFF));
  248.         }
  249.         printf("\"\nimstring=\"");
  250.  
  251.         for (uint32_t i = 0; i < compressed.size(); i++)
  252.         {
  253.             putchar(NoEscape(compressed[i] + ASCOFF));
  254.         }
  255.         printf("\"\n");
  256.  
  257.         printf("Compressed size %i\n", compressed.size());
  258.  
  259.         fclose(file);
  260.     }
  261.     else
  262.     {
  263.         printf("Could not open file.\n");
  264.     }
  265.     return 0;
  266. }
  267.  
  268.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement