home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 609b.lha / MandelSquare_v1.3 / Source.LZH / Source / SaveAnim / skip.c < prev   
Encoding:
C/C++ Source or Header  |  1992-01-06  |  11.4 KB  |  480 lines

  1. /***************************************************************************
  2. *
  3. *  This contains routines to compress images one of two ways:
  4. *      1. Vertical Byte Run Length (VRUN)
  5. *      2. Vertical Byte Run Length With Skips (SKIP)
  6. *   from amiga/programs #274, dated jul 8 1987...
  7. *
  8. * The routines here compress a single bit-plane.  There's routines to
  9. * see how big the compressed result will be (xxxx_count_plane() )
  10. * and routines to actually compress the result into a buffer in memory
  11. * (xxxx_comp_plane() )  where xxxx is either vrun or skip depending....
  12. *
  13. *
  14. * VRUN compression format:
  15. *    a VRUN-compressed plane is a concatenation of VRUN-compressed columns.
  16. *    Each column is an op-count followed by a concatenation of op-count op's.
  17. *    An op is in one of these two formats:
  18. *        SAME_OP:  1-byte-count  followed by 1-byte to repeat count times.
  19. *        UNIQ_OP:  1-byte-count  followed by count bytes of data to copy
  20. *    The counts in either op must be 127 or less.  If it's a UNIQ_OP the
  21. *    hi bit of the count op is set (it's masked with 127 to find the actual
  22. *    count).
  23. *
  24. * SKIP compression format:
  25. *    a SKIP compressed plane is a concatenation of SKIP-compressed columns.
  26. *    Like a VRUN this is an op-count followed by a concatenation of op;s.
  27. *    However in this one we have 3 op formats:
  28. *       SKIP_OP:  Hi bit clear.  Count of bytes to skip.
  29. *       UNIQ_OP:  Hi bit set.  Remainder is count of data to copy. Data
  30. *                 follows immediately.
  31. *       SAME_OP:  A zero followed by a one-byte-count followed by one byte
  32. *                 of data to repeat count times.
  33. *
  34. ***************************************************************************/
  35.  
  36. #include <exec/types.h>
  37. #include <graphics/gfx.h>
  38.  
  39. #define MAXRUN 127
  40.  
  41. static WORD linebytes = 40;
  42. static WORD uniq_count;
  43. static unsigned char *uniq;
  44. static WORD op_count;
  45.  
  46.  
  47. /* count up how many in a column are the same between in and last_in ...
  48.    ie how big of a "skip" can we go on. */
  49. WORD
  50. vskip(in, last_in,  count)
  51. register unsigned char *in;
  52. register unsigned char *last_in;
  53. register WORD count;
  54. {
  55. register WORD skips;
  56.  
  57. skips = 0;
  58. while (--count >= 0) {
  59.     if (*in != *last_in)
  60.         break;
  61.     in += linebytes;
  62.     last_in += linebytes;
  63.     skips++;
  64. }
  65. return(skips);
  66. }
  67.  
  68. /* vsame() - count up how many in a row (vertically) are the same as the
  69.    first one ... ie how big of a "same" op we can have */
  70. WORD
  71. vsame(in,  count)
  72. register unsigned char *in;
  73. register WORD count;
  74. {
  75. register unsigned char c;
  76. register WORD same;
  77.  
  78. c = *in;
  79. in += linebytes;
  80. --count;
  81. same = 1;
  82. while (--count >= 0)
  83.     {
  84.     if (*in != c)
  85.         break;
  86.     same++;
  87.     in += linebytes;
  88.     }
  89. return(same);
  90. }
  91.  
  92.  
  93. /* skip_count_line() - figure out what size this column will compress
  94.    to using vertical-byte-run-length-with-skips encoding */
  95. WORD
  96. skip_count_line(in, last_in, count)
  97. register unsigned char *in;
  98. register unsigned char *last_in;
  99. WORD  count;
  100. {
  101. WORD local_count;
  102. WORD a_run;
  103. WORD run_length;
  104. WORD uniq_count = 0;
  105. WORD comp_count = 1; /* one for the op count */
  106.  
  107.  
  108. if (vskip(in, last_in, count) == count)  /* skip whole column? */
  109.     return(1);
  110. for (;;) {
  111.     if (count <= 0)
  112.         break;
  113.     local_count = (count < MAXRUN ? count : MAXRUN);
  114.     a_run = 0;
  115.     if ((run_length = vskip(in, last_in, local_count)) > 1) {
  116.         count -= run_length;
  117.         if (count > 0)    /* the last skip disappears */
  118.             comp_count += 1;
  119.         a_run = 1;
  120.     }
  121.     else if ((run_length = vsame(in, local_count)) > 3) {
  122.         count -= run_length;
  123.         a_run = 1;
  124.         comp_count += 3;
  125.     }
  126.     if (a_run) {
  127.         in += run_length*linebytes;
  128.         last_in += run_length*linebytes;
  129.         if (uniq_count > 0) {
  130.             comp_count += uniq_count+1;
  131.             uniq_count = 0;
  132.         }
  133.     } else {
  134.         in += linebytes;
  135.         last_in += linebytes;
  136.         uniq_count++;
  137.         count -= 1;
  138.         if (uniq_count == MAXRUN) {
  139.             comp_count += uniq_count+1;
  140.             uniq_count = 0;
  141.         }
  142.     }
  143. }
  144. if (count != 0) {
  145. /*    printf("weird end count %d in skip_line_count\n");*/
  146. }
  147. if (uniq_count != 0) {
  148.     comp_count += uniq_count+1;
  149. }
  150. return(comp_count);
  151. }
  152.  
  153. /* skip_count_plane() - figure out what size this plane will compress
  154.    to using vertical-byte-run-length-with-skips encoding */
  155. WORD
  156. skip_count_plane(in, last_in, next_line, rows)
  157. unsigned char *in;
  158. unsigned char *last_in;
  159. WORD  next_line;
  160. WORD  rows;
  161. {
  162. WORD i;
  163. WORD comp_count;
  164.  
  165. linebytes = next_line;
  166. comp_count = 0;
  167. i = next_line;
  168. while (--i >= 0)
  169.     {
  170.     comp_count += skip_count_line(in, last_in, rows);
  171.     in++;
  172.     last_in++;
  173.     }
  174. return(comp_count);
  175. }
  176.  
  177. /* flush_uniq() - write out the "uniq" run that's been accumulating while
  178.    we've been looking for skips and "same" runs. */
  179. unsigned char *
  180. flush_uniq(stuff)
  181. unsigned char *stuff;
  182. {
  183. if (uniq_count > 0)
  184.     {
  185.     op_count++;
  186.     *stuff++ = (uniq_count | 0x80);
  187.     copy_line_to_chars(uniq, stuff, linebytes, uniq_count);
  188.     stuff += uniq_count;
  189.     uniq_count = 0;
  190.     }
  191. return(stuff);
  192. }
  193.  
  194. int
  195. copy_line_to_chars(in,out,linebytes,count)
  196. unsigned char *in,*out;
  197. int linebytes,count;
  198. {
  199.    while (count--) {
  200.       *out = *in;
  201.       out++;
  202.       in += linebytes;
  203.    }
  204.    return(0);
  205. }
  206.  
  207. /* skip_comp_line() - Compress "in" into "out" using vertical-byte-run-
  208.    with-skips encodeing. Return pointer to "out"'s next free space. */
  209. unsigned char *
  210. skip_comp_line(in, last_in, out, count)
  211. register unsigned char *in;
  212. unsigned char *last_in;
  213. unsigned char *out;
  214. WORD  count;
  215. {
  216. register unsigned char *stuffit;
  217. WORD local_count;
  218. WORD a_run;
  219. WORD run_length;
  220.  
  221. /* if can skip over whole column, then compact a bit by just setting the
  222.    "op count" for this column to zero */
  223. if (vskip(in, last_in, count) == count)  /* skip whole column? */ {
  224.     *out++ = 0;
  225.     return(out);
  226. }
  227.  
  228. op_count = 0;    /* haven't done any op's yet */
  229.  
  230. /* initialize variables which keep track of how many uniq bytes we've gone
  231.    past, and where uniq run started. */
  232. uniq_count = 0;
  233. uniq = in;
  234.  
  235. stuffit = out+1; /* skip past "op-count" slot in out array */
  236. for (;;) {
  237.     if (count <= 0)
  238.         break;
  239.     local_count = (count < MAXRUN ? count : MAXRUN);
  240.     a_run = 0;  /* first assume not a skip or a same run */
  241.     /* see how much could skip from here.  Two or more is worth skipping! */
  242.     if ((run_length = vskip(in, last_in, local_count)) > 1) {
  243.         a_run = 1;
  244.         count -= run_length;
  245.         stuffit = flush_uniq(stuffit); /* flush pending "uniq" run */
  246.         if (count > 0)    /* last skip vanishes */ {
  247.             op_count++;
  248.             *stuffit++ = run_length;
  249.         }
  250.     }
  251.     /* four or more of the same byte in a row compresses too */
  252.     else if ((run_length = vsame(in, local_count)) > 3) {
  253.         a_run = 1;
  254.         count -= run_length;
  255.         op_count++;
  256.         stuffit = flush_uniq(stuffit); /* flush pending "uniq" run */
  257.         *stuffit++ = 0;
  258.         *stuffit++ = run_length;
  259.         *stuffit++ = *in;
  260.     }
  261.     /* if it's a run of some sort update in and last_in pointer, and
  262.        reset the uniq pointer to the current position */
  263.     if (a_run) {
  264.         in += run_length*linebytes;
  265.         last_in += run_length*linebytes;
  266.         uniq = in;
  267.     /* otherwise just continue accumulating stuff in uniq for later flushing
  268.        or immediate if it get's past MAXRUN */
  269.     } else {
  270.         in += linebytes;
  271.         last_in += linebytes;
  272.         uniq_count++;
  273.         count -= 1;
  274.         if (uniq_count == MAXRUN) {
  275.             stuffit = flush_uniq(stuffit);
  276.             uniq = in;
  277.         }
  278.     }
  279. }
  280. /* if came to end of column within a uniq-run still have to flush it */
  281. if (uniq_count != 0) {
  282.     stuffit = flush_uniq(stuffit);
  283. }
  284. if (count != 0) {
  285. /*    printf("weird end count %d in skip_line_count\n", count);*/
  286. }
  287. /* and stuff the first byte of this (compressed) column with the op_count */
  288. *out = op_count;
  289. return(stuffit);
  290. }
  291.  
  292. /* skip_comp_plane() - Compress "in" into "out" using vertical-byte-run-
  293.    with-skips encodeing. Return pointer to "out"'s next free space. */
  294. unsigned char *
  295. skip_comp_plane(in, last_in, out, next_line, rows)
  296. unsigned char *in;
  297. unsigned char *last_in;
  298. unsigned char *out;
  299. WORD  next_line;
  300. WORD  rows;
  301. {
  302. WORD i;
  303. unsigned char *last_out = out;
  304.  
  305. linebytes = next_line;
  306. i = next_line;
  307. while (--i >= 0) {
  308.     out = skip_comp_line(in, last_in, out, rows);
  309.     last_out = out;
  310.     in++;
  311.     last_in++;
  312. }
  313. return(out);
  314. }
  315.  
  316. /* vrun_count_line() - figure out what size this column will compress
  317.    to using vertical-byte-run-length encoding */
  318. WORD
  319. vrun_count_line(in, count)
  320. register unsigned char *in;
  321. WORD  count;
  322. {
  323. WORD local_count;
  324. WORD a_run;
  325. WORD run_length;
  326. WORD uniq_count = 0;
  327. WORD comp_count = 1; /* one for the op count */
  328.  
  329.  
  330. for (;;)
  331.     {
  332.     if (count <= 0)
  333.         break;
  334.     local_count = (count < MAXRUN ? count : MAXRUN);
  335.     a_run = 0;
  336.     if ((run_length = vsame(in, local_count)) > 2)
  337.         {
  338.         a_run = 1;
  339.         comp_count += 2;
  340.         }
  341.     if (a_run)
  342.         {
  343.         in += run_length*linebytes;
  344.         count -= run_length;
  345.         if (uniq_count > 0)
  346.             {
  347.             comp_count += uniq_count+1;
  348.             uniq_count = 0;
  349.             }
  350.         }
  351.     else
  352.         {
  353.         in += linebytes;
  354.         uniq_count++;
  355.         count -= 1;
  356.         if (uniq_count == MAXRUN)
  357.             {
  358.             comp_count += uniq_count+1;
  359.             uniq_count = 0;
  360.             }
  361.         }
  362.     }
  363. if (count != 0)
  364.     {
  365. /*    printf("weird end count %d in vrun_line_count\n");*/
  366.     }
  367. if (uniq_count != 0)
  368.     {
  369.     comp_count += uniq_count+1;
  370.     }
  371. return(comp_count);
  372. }
  373.  
  374. /* vrun_count_plane() - figure out what size this plane will compress
  375.    to using vertical-byte-run-length encoding */
  376. WORD
  377. vrun_count_plane(in, next_line, rows)
  378. unsigned char *in;
  379. WORD  next_line;
  380. WORD  rows;
  381. {
  382. WORD i;
  383. WORD comp_count;
  384.  
  385. linebytes = next_line;
  386. comp_count = 0;
  387. i = next_line;
  388. while (--i >= 0)
  389.     {
  390.     comp_count += vrun_count_line(in, rows);
  391.     in++;
  392.     }
  393. return(comp_count);
  394. }
  395.  
  396.  
  397. /* vrun_comp_line() - Compress "in" into "out" using vertical-byte-run
  398.    encodeing. Return pointer to "out"'s next free space. */
  399. unsigned char *
  400. vrun_comp_line(in, out, count)
  401. register unsigned char *in;
  402. unsigned char *out;
  403. WORD  count;
  404. {
  405. register unsigned char *stuffit;
  406. WORD local_count;
  407. WORD a_run;
  408. WORD run_length;
  409.  
  410. uniq_count = op_count = 0;
  411. uniq = in;
  412.  
  413. stuffit = out+1;
  414. for (;;)
  415.     {
  416.     if (count <= 0)
  417.         break;
  418.     local_count = (count < MAXRUN ? count : MAXRUN);
  419.     a_run = 0;
  420.     if ((run_length = vsame(in, local_count)) > 2)
  421.         {
  422.         a_run = 1;
  423.         stuffit = flush_uniq(stuffit);
  424.         *stuffit++ = run_length;
  425.         *stuffit++ = *in;
  426.         }
  427.     if (a_run)
  428.         {
  429.         op_count++;
  430.         in += run_length*linebytes;
  431.         count -= run_length;
  432.         uniq = in;
  433.         }
  434.     else
  435.         {
  436.         in += linebytes;
  437.         uniq_count++;
  438.         count -= 1;
  439.         if (uniq_count == MAXRUN)
  440.             {
  441.             stuffit = flush_uniq(stuffit);
  442.             uniq = in;
  443.             }
  444.         }
  445.     }
  446. if (uniq_count != 0)
  447.     {
  448.     stuffit = flush_uniq(stuffit);
  449.     }
  450. if (count != 0)
  451.     {
  452. /*    printf("weird end count %d in vrun_line_count\n", count);*/
  453.     }
  454. *out = op_count;
  455. return(stuffit);
  456. }
  457.  
  458. /* vrun_comp_plane() - Compress "in" into "out" using vertical-byte-run
  459.    encodeing. Return pointer to "out"'s next free space. */
  460. unsigned char *
  461. vrun_comp_plane(in, out, next_line, rows)
  462. unsigned char *in;
  463. unsigned char *out;
  464. WORD  next_line;
  465. WORD  rows;
  466. {
  467. WORD i;
  468. unsigned char *last_out = out;
  469.  
  470. linebytes = next_line;
  471. i = next_line;
  472. while (--i >= 0)
  473.     {
  474.     out = vrun_comp_line(in, out, rows);
  475.     last_out = out;
  476.     in++;
  477.     }
  478. return(out);
  479. }
  480.