home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gfli / fli.c next >
Encoding:
C/C++ Source or Header  |  1999-09-14  |  20.0 KB  |  722 lines

  1.  
  2. /*
  3.  * Written 1998 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20.  
  21. /*
  22.  * This code can be used to read and write FLI movies. It is currently
  23.  * only used for the GIMP fli plug-in, but it can be used for other
  24.  * programs, too.
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "fli.h"
  32.  
  33. /*
  34.  * To avoid endian-problems I wrote these functions:
  35.  */
  36. static unsigned char fli_read_char(FILE *f)
  37. {
  38.     unsigned char b;
  39.     fread(&b,1,1,f);
  40.     return b;
  41. }
  42.  
  43. static unsigned short fli_read_short(FILE *f)
  44. {
  45.     unsigned char b[2];
  46.     fread(&b,1,2,f);
  47.     return (unsigned short)(b[1]<<8) | b[0];
  48. }
  49.  
  50. static unsigned long fli_read_long(FILE *f)
  51. {
  52.     unsigned char b[4];
  53.     fread(&b,1,4,f);
  54.     return (unsigned long)(b[3]<<24) | (b[2]<<16) | (b[1]<<8) | b[0];
  55. }
  56.  
  57. static void fli_write_char(FILE *f, unsigned char b)
  58. {
  59.     fwrite(&b,1,1,f);
  60. }
  61.  
  62. static void fli_write_short(FILE *f, unsigned short w)
  63. {
  64.     unsigned char b[2];
  65.     b[0]=w&255;
  66.     b[1]=(w>>8)&255;
  67.     fwrite(&b,1,2,f);
  68. }
  69.  
  70. static void fli_write_long(FILE *f, unsigned long l)
  71. {
  72.     unsigned char b[4];
  73.     b[0]=l&255;
  74.     b[1]=(l>>8)&255;
  75.     b[2]=(l>>16)&255;
  76.     b[3]=(l>>24)&255;
  77.     fwrite(&b,1,4,f);
  78. }
  79.  
  80. void fli_read_header(FILE *f, s_fli_header *fli_header)
  81. {
  82.     fli_header->filesize=fli_read_long(f);    /* 0 */
  83.     fli_header->magic=fli_read_short(f);    /* 4 */
  84.     fli_header->frames=fli_read_short(f);    /* 6 */
  85.     fli_header->width=fli_read_short(f);    /* 8 */
  86.     fli_header->height=fli_read_short(f);    /* 10 */
  87.     fli_header->depth=fli_read_short(f);    /* 12 */
  88.     fli_header->flags=fli_read_short(f);    /* 14 */
  89.     if (fli_header->magic == HEADER_FLI) {
  90.         /* FLI saves speed in 1/70s */
  91.         fli_header->speed=fli_read_short(f)*14;        /* 16 */
  92.     } else {
  93.         if (fli_header->magic == HEADER_FLC) {
  94.             /* FLC saves speed in 1/1000s */
  95.             fli_header->speed=fli_read_long(f);    /* 16 */
  96.         } else {
  97.             fprintf(stderr, "error: magic number is wrong !\n");
  98.             fli_header->magic = NO_HEADER;
  99.         }
  100.     }
  101. }
  102.  
  103. void fli_write_header(FILE *f, s_fli_header *fli_header)
  104. {
  105.     fli_header->filesize=ftell(f);
  106.     fseek(f, 0, SEEK_SET);
  107.     fli_write_long(f, fli_header->filesize);    /* 0 */
  108.     fli_write_short(f, fli_header->magic);    /* 4 */
  109.     fli_write_short(f, fli_header->frames);    /* 6 */
  110.     fli_write_short(f, fli_header->width);    /* 8 */
  111.     fli_write_short(f, fli_header->height);    /* 10 */
  112.     fli_write_short(f, fli_header->depth);    /* 12 */
  113.     fli_write_short(f, fli_header->flags);    /* 14 */
  114.     if (fli_header->magic == HEADER_FLI) {
  115.         /* FLI saves speed in 1/70s */
  116.         fli_write_short(f, fli_header->speed / 14);    /* 16 */
  117.     } else {
  118.         if (fli_header->magic == HEADER_FLC) {
  119.             /* FLC saves speed in 1/1000s */
  120.             fli_write_long(f, fli_header->speed);    /* 16 */
  121.             fseek(f, 80, SEEK_SET);
  122.             fli_write_long(f, fli_header->oframe1);    /* 80 */
  123.             fli_write_long(f, fli_header->oframe2);    /* 84 */
  124.         } else {
  125.             fprintf(stderr, "error: magic number in header is wrong !\n");
  126.         }
  127.     }
  128. }
  129.  
  130. void fli_read_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap)
  131. {
  132.     s_fli_frame fli_frame;
  133.     unsigned long framepos;
  134.     int c;
  135.     framepos=ftell(f);
  136.  
  137.     fli_frame.size=fli_read_long(f);
  138.     fli_frame.magic=fli_read_short(f);
  139.     fli_frame.chunks=fli_read_short(f);
  140.  
  141.     if (fli_frame.magic == FRAME) {
  142.         fseek(f, framepos+16, SEEK_SET);
  143.         for (c=0;c<fli_frame.chunks;c++) {
  144.             s_fli_chunk chunk;
  145.             unsigned long chunkpos;
  146.             chunkpos = ftell(f);
  147.             chunk.size=fli_read_long(f);
  148.             chunk.magic=fli_read_short(f);
  149.             switch (chunk.magic) {
  150.                 case FLI_COLOR:   fli_read_color(f, fli_header, old_cmap, cmap); break;
  151.                 case FLI_COLOR_2: fli_read_color_2(f, fli_header, old_cmap, cmap); break;
  152.                 case FLI_BLACK:      fli_read_black(f, fli_header, framebuf); break;
  153.                 case FLI_BRUN:    fli_read_brun(f, fli_header, framebuf); break;
  154.                 case FLI_COPY:    fli_read_copy(f, fli_header, framebuf); break;
  155.                 case FLI_LC:      fli_read_lc(f, fli_header, old_framebuf, framebuf); break;
  156.                 case FLI_LC_2:    fli_read_lc_2(f, fli_header, old_framebuf, framebuf); break;
  157.                 case FLI_MINI:      /* unused, skip */ break;
  158.                 default: /* unknown, skip */ break;
  159.             }
  160.             if (chunk.size & 1) chunk.size++;
  161.             fseek(f,chunkpos+chunk.size,SEEK_SET);
  162.         }
  163.     } /* else: unknown, skip */ 
  164.     fseek(f, framepos+fli_frame.size, SEEK_SET);
  165. }
  166.  
  167. void fli_write_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap, unsigned short codec_mask)
  168. {
  169.     s_fli_frame fli_frame;
  170.     unsigned long framepos, frameend;
  171.     framepos=ftell(f);
  172.     fseek(f, framepos+16, SEEK_SET);
  173.  
  174.     switch (fli_header->frames) {
  175.         case 0: fli_header->oframe1=framepos; break;
  176.         case 1: fli_header->oframe2=framepos; break;
  177.     }
  178.  
  179.     fli_frame.size=0;
  180.     fli_frame.magic=FRAME;
  181.     fli_frame.chunks=0;
  182.  
  183.     /* 
  184.      * create color chunk 
  185.      */
  186.     if (fli_header->magic == HEADER_FLI) {
  187.         if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
  188.     } else {
  189.         if (fli_header->magic == HEADER_FLC) {
  190.             if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
  191.         } else {
  192.             fprintf(stderr, "error: magic number in header is wrong !\n");
  193.         }
  194.     }
  195.  
  196. #if 0
  197.     if (codec_mask & W_COLOR) {
  198.         if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
  199.     }
  200.     if (codec_mask & W_COLOR_2) {
  201.         if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
  202.     }
  203. #endif
  204.     /* create bitmap chunk */
  205.     if (old_framebuf==NULL) {
  206.         fli_write_brun(f, fli_header, framebuf);
  207.     } else {
  208.         fli_write_lc(f, fli_header, old_framebuf, framebuf);
  209.     }
  210.     fli_frame.chunks++;
  211.     
  212.     frameend=ftell(f);
  213.     fli_frame.size=frameend-framepos;
  214.     fseek(f, framepos, SEEK_SET);
  215.     fli_write_long(f, fli_frame.size);
  216.     fli_write_short(f, fli_frame.magic);
  217.     fli_write_short(f, fli_frame.chunks);
  218.     fseek(f, frameend, SEEK_SET);
  219.     fli_header->frames++;
  220. }
  221.  
  222. /*
  223.  * palette chunks from the classical Autodesk Animator.
  224.  */
  225. void fli_read_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
  226. {
  227.     unsigned short num_packets, cnt_packets, col_pos;
  228.     col_pos=0;
  229.     num_packets=fli_read_short(f);
  230.     for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
  231.         unsigned short skip_col, num_col, col_cnt;
  232.         skip_col=fli_read_char(f);
  233.         num_col=fli_read_char(f);
  234.         if (num_col==0) {
  235.             for (col_pos=0; col_pos<768; col_pos++) {
  236.                 cmap[col_pos]=fli_read_char(f)<<2;
  237.             }
  238.             return;
  239.         }
  240.         for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
  241.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  242.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  243.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  244.         }
  245.         for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
  246.             cmap[col_pos++]=fli_read_char(f)<<2;
  247.             cmap[col_pos++]=fli_read_char(f)<<2;
  248.             cmap[col_pos++]=fli_read_char(f)<<2;
  249.         }
  250.     }
  251. }
  252.  
  253. int fli_write_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
  254. {
  255.     unsigned long chunkpos;
  256.     unsigned short num_packets;
  257.     s_fli_chunk chunk; 
  258.     chunkpos=ftell(f);
  259.     fseek(f, chunkpos+8, SEEK_SET);
  260.     num_packets=0;
  261.     if (old_cmap==NULL) {
  262.         unsigned short col_pos;
  263.         num_packets=1;
  264.         fli_write_char(f, 0); /* skip no color */
  265.         fli_write_char(f, 0); /* 256 color */
  266.         for (col_pos=0; col_pos<768; col_pos++) {
  267.             fli_write_char(f, cmap[col_pos]>>2);
  268.         }
  269.     } else {
  270.         unsigned short num_packets, cnt_skip, cnt_col, col_pos, col_start;
  271.         num_packets=0; col_pos=0;
  272.         do {
  273.             cnt_skip=0; 
  274.             while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
  275.                 cnt_skip++; col_pos++;
  276.             }
  277.             col_start=col_pos;
  278.             cnt_col=0; 
  279.             while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
  280.                 cnt_col++; col_pos++;
  281.             }
  282.             if (cnt_col>0) {
  283.                 num_packets++;
  284.                 fli_write_char(f, cnt_skip & 255);
  285.                 fli_write_char(f, cnt_col & 255);
  286.                 while (cnt_col>0) {
  287.                     fli_write_char(f, cmap[col_start++]>>2);
  288.                     fli_write_char(f, cmap[col_start++]>>2);
  289.                     fli_write_char(f, cmap[col_start++]>>2);
  290.                     cnt_col--;
  291.                 }
  292.             }
  293.         } while (col_pos<256);
  294.     }
  295.  
  296.     if (num_packets>0) {
  297.         chunk.size=ftell(f)-chunkpos;
  298.         chunk.magic=FLI_COLOR;
  299.  
  300.         fseek(f, chunkpos, SEEK_SET);
  301.         fli_write_long(f, chunk.size);
  302.         fli_write_short(f, chunk.magic);
  303.         fli_write_short(f, num_packets);
  304.  
  305.         if (chunk.size & 1) chunk.size++;
  306.         fseek(f,chunkpos+chunk.size,SEEK_SET);
  307.         return 1;
  308.     }
  309.     fseek(f,chunkpos, SEEK_SET);
  310.     return 0;
  311. }
  312.  
  313. /*
  314.  * palette chunks from Autodesk Animator pro
  315.  */
  316. void fli_read_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
  317. {
  318.     unsigned short num_packets, cnt_packets, col_pos;
  319.     num_packets=fli_read_short(f);
  320.     col_pos=0;
  321.     for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
  322.         unsigned short skip_col, num_col, col_cnt;
  323.         skip_col=fli_read_char(f);
  324.         num_col=fli_read_char(f);
  325.         if (num_col == 0) {
  326.             for (col_pos=0; col_pos<768; col_pos++) {
  327.                 cmap[col_pos]=fli_read_char(f);
  328.             }
  329.             return;
  330.         } 
  331.         for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
  332.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  333.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  334.             cmap[col_pos]=old_cmap[col_pos];col_pos++;
  335.         }
  336.         for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
  337.             cmap[col_pos++]=fli_read_char(f);                
  338.             cmap[col_pos++]=fli_read_char(f);
  339.             cmap[col_pos++]=fli_read_char(f);
  340.         }
  341.     }
  342. }
  343.  
  344. int fli_write_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
  345. {
  346.     unsigned long chunkpos;
  347.     unsigned short num_packets;
  348.     s_fli_chunk chunk; 
  349.     chunkpos=ftell(f);
  350.     fseek(f, chunkpos+8, SEEK_SET);
  351.     num_packets=0;
  352.     if (old_cmap==NULL) {
  353.         unsigned short col_pos;
  354.         num_packets=1;
  355.         fli_write_char(f, 0); /* skip no color */
  356.         fli_write_char(f, 0); /* 256 color */
  357.         for (col_pos=0; col_pos<768; col_pos++) {
  358.             fli_write_char(f, cmap[col_pos]);
  359.         }
  360.     } else {
  361.         unsigned short num_packets, cnt_skip, cnt_col, col_pos, col_start;
  362.         num_packets=0; col_pos=0;
  363.         do {
  364.             cnt_skip=0; 
  365.             while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
  366.                 cnt_skip++; col_pos++;
  367.             }
  368.             col_start=col_pos;
  369.             cnt_col=0; 
  370.             while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
  371.                 cnt_col++; col_pos++;
  372.             }
  373.             if (cnt_col>0) {
  374.                 num_packets++;
  375.                 fli_write_char(f, cnt_skip);
  376.                 fli_write_char(f, cnt_col);
  377.                 for (; cnt_col>0; cnt_col--) {
  378.                     fli_write_char(f, cmap[col_start++]);
  379.                     fli_write_char(f, cmap[col_start++]);
  380.                     fli_write_char(f, cmap[col_start++]);
  381.                 }
  382.             }
  383.         } while (col_pos<256);
  384.     }
  385.  
  386.     if (num_packets>0) {
  387.         chunk.size=ftell(f)-chunkpos;
  388.         chunk.magic=FLI_COLOR_2;
  389.  
  390.         fseek(f, chunkpos, SEEK_SET);
  391.         fli_write_long(f, chunk.size);
  392.         fli_write_short(f, chunk.magic);
  393.         fli_write_short(f, num_packets);
  394.  
  395.         if (chunk.size & 1) chunk.size++;
  396.         fseek(f,chunkpos+chunk.size,SEEK_SET);
  397.         return 1;
  398.     }
  399.     fseek(f,chunkpos, SEEK_SET);
  400.     return 0;
  401. }
  402.  
  403. /*
  404.  * completely black frame
  405.  */
  406. void fli_read_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  407. {
  408.     memset(framebuf, 0, fli_header->width * fli_header->height);
  409. }
  410.  
  411. void fli_write_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  412. {
  413.     s_fli_chunk chunk; 
  414.  
  415.     chunk.size=6;
  416.     chunk.magic=FLI_BLACK;
  417.  
  418.     fli_write_long(f, chunk.size);
  419.     fli_write_short(f, chunk.magic);
  420. }
  421.  
  422. /*
  423.  * Uncompressed frame
  424.  */
  425. void fli_read_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  426. {
  427.     fread(framebuf, fli_header->width, fli_header->height, f);
  428. }
  429.  
  430. void fli_write_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  431. {
  432.     
  433.     unsigned long chunkpos;
  434.     s_fli_chunk chunk; 
  435.     chunkpos=ftell(f);
  436.     fseek(f, chunkpos+6, SEEK_SET);
  437.     fwrite(framebuf, fli_header->width, fli_header->height, f);
  438.     chunk.size=ftell(f)-chunkpos;
  439.     chunk.magic=FLI_COPY;
  440.  
  441.     fseek(f, chunkpos, SEEK_SET);
  442.     fli_write_long(f, chunk.size);
  443.     fli_write_short(f, chunk.magic);
  444.     
  445.     if (chunk.size & 1) chunk.size++;
  446.     fseek(f,chunkpos+chunk.size,SEEK_SET);
  447. }
  448.  
  449. /*
  450.  * This is a RLE algorithm, used for the first image of an animation
  451.  */
  452. void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  453. {
  454.     unsigned short yc;
  455.     unsigned char *pos;
  456.     for (yc=0; yc < fli_header->height; yc++) {
  457.         unsigned short xc, pc, pcnt;
  458.         pc=fli_read_char(f);
  459.         xc=0;
  460.         pos=framebuf+(fli_header->width * yc);
  461.         for (pcnt=pc; pcnt>0; pcnt--) {
  462.             unsigned short ps;
  463.             ps=fli_read_char(f);
  464.             if (ps & 0x80) {
  465.                 unsigned short len; 
  466.                 for (len=-(signed char)ps; len>0; len--) {
  467.                     pos[xc++]=fli_read_char(f);
  468.                 } 
  469.             } else {
  470.                 unsigned char val;
  471.                 val=fli_read_char(f);
  472.                 memset(&(pos[xc]), val, ps);
  473.                 xc+=ps;
  474.             }
  475.         }
  476.     } 
  477. }
  478.  
  479. void fli_write_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
  480. {
  481.     unsigned long chunkpos;
  482.     s_fli_chunk chunk; 
  483.     unsigned short yc;
  484.     unsigned char *linebuf;
  485.     
  486.     chunkpos=ftell(f);
  487.     fseek(f, chunkpos+6, SEEK_SET);
  488.  
  489.     for (yc=0; yc < fli_header->height; yc++) {
  490.         unsigned short xc, t1, pc, tc;
  491.         unsigned long linepos, lineend, bc;
  492.         linepos=ftell(f); bc=0;
  493.         fseek(f, 1, SEEK_CUR);
  494.         linebuf=framebuf + (yc*fli_header->width);
  495.         xc=0; tc=0; t1=0;
  496.         while (xc < fli_header->width) {
  497.             pc=1;
  498.             while ((pc<120) && ((xc+pc)<fli_header->width) && (linebuf[xc+pc] == linebuf[xc])) {
  499.                 pc++; 
  500.             }
  501.             if (pc>2) {
  502.                 if (tc>0) {
  503.                     bc++;
  504.                     fli_write_char(f, (tc-1)^0xFF);
  505.                     fwrite(linebuf+t1, 1, tc, f);
  506.                     tc=0;
  507.                 }
  508.                 bc++;
  509.                 fli_write_char(f, pc);
  510.                 fli_write_char(f, linebuf[xc]);
  511.                 t1=xc+pc;
  512.             } else {
  513.                 tc+=pc;
  514.                 if (tc>120) {
  515.                     bc++;
  516.                     fli_write_char(f, (tc-1)^0xFF);
  517.                     fwrite(linebuf+t1, 1, tc, f);
  518.                     tc=0;
  519.                     t1=xc+pc;
  520.                 }
  521.             }
  522.             xc+=pc;
  523.         }
  524.         if (tc>0) {
  525.             bc++;
  526.             fli_write_char(f, (tc-1)^0xFF);
  527.             fwrite(linebuf+t1, 1, tc, f);
  528.             tc=0;
  529.         }
  530.         lineend=ftell(f); 
  531.         fseek(f, linepos, SEEK_SET);
  532.         fli_write_char(f, bc);
  533.         fseek(f, lineend, SEEK_SET);
  534.     }
  535.  
  536.     chunk.size=ftell(f)-chunkpos;
  537.     chunk.magic=FLI_BRUN;
  538.  
  539.     fseek(f, chunkpos, SEEK_SET);
  540.     fli_write_long(f, chunk.size);
  541.     fli_write_short(f, chunk.magic);
  542.     
  543.     if (chunk.size & 1) chunk.size++;
  544.     fseek(f,chunkpos+chunk.size,SEEK_SET);
  545. }
  546.  
  547. /*
  548.  * This is the delta-compression method from the classic Autodesk Animator. 
  549.  * It's basically the RLE method from above, but it allows to skip unchanged
  550.  * lines at the beginning and end of an image, and unchanged pixels in a line
  551.  * This chunk is used in FLI files.
  552.  */
  553. void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
  554. {
  555.     unsigned short yc, firstline, numline;
  556.     unsigned char *pos;
  557.     memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
  558.     firstline = fli_read_short(f);
  559.     numline = fli_read_short(f);
  560.     for (yc=0; yc < numline; yc++) {
  561.         unsigned short xc, pc, pcnt;
  562.         pc=fli_read_char(f);
  563.         xc=0;
  564.         pos=framebuf+(fli_header->width * (firstline+yc));
  565.         for (pcnt=pc; pcnt>0; pcnt--) {
  566.             unsigned short ps,skip;
  567.             skip=fli_read_char(f);
  568.             ps=fli_read_char(f);
  569.             xc+=skip;
  570.             if (ps & 0x80) {
  571.                 unsigned char val;
  572.                 ps=-(signed char)ps;
  573.                 val=fli_read_char(f);
  574.                 memset(&(pos[xc]), val, ps);
  575.                 xc+=ps;
  576.             } else {
  577.                 fread(&(pos[xc]), ps, 1, f);
  578.                 xc+=ps;
  579.             }
  580.         }
  581.     } 
  582. }
  583.  
  584. void fli_write_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
  585. {
  586.     unsigned long chunkpos;
  587.     s_fli_chunk chunk; 
  588.     unsigned short yc, firstline, numline, lastline;
  589.     unsigned char *linebuf, *old_linebuf;
  590.     
  591.     chunkpos=ftell(f);
  592.     fseek(f, chunkpos+6, SEEK_SET);
  593.  
  594.     /* first check, how many lines are unchanged at the beginning */
  595.     firstline=0;
  596.     while ((memcmp(old_framebuf+(firstline*fli_header->width), framebuf+(firstline*fli_header->width), fli_header->width)==0) && (firstline<fli_header->height)) firstline++;
  597.     
  598.     /* then check from the end, how many lines are unchanged */
  599.     if (firstline<fli_header->height) {
  600.         lastline=fli_header->height-1;
  601.         while ((memcmp(old_framebuf+(lastline*fli_header->width), framebuf+(lastline*fli_header->width), fli_header->width)==0) && (lastline>firstline)) lastline--;
  602.         numline=(lastline-firstline)+1;
  603.     } else {
  604.         numline=0; 
  605.     }
  606.     if (numline==0) firstline=0;
  607.  
  608.     fli_write_short(f, firstline);
  609.     fli_write_short(f, numline);
  610.  
  611.     for (yc=0; yc < numline; yc++) {
  612.         unsigned short xc, sc, cc, tc;
  613.         unsigned long linepos, lineend, bc;
  614.         linepos=ftell(f); bc=0;
  615.         fseek(f, 1, SEEK_CUR);
  616.  
  617.         linebuf=framebuf + ((firstline+yc)*fli_header->width);
  618.         old_linebuf=old_framebuf + ((firstline+yc)*fli_header->width);
  619.         xc=0;
  620.         while (xc < fli_header->width) {
  621.             sc=0;
  622.             while ((linebuf[xc]==old_linebuf[xc]) && (xc<fli_header->width) && (sc<255)) {
  623.                 xc++; sc++;
  624.             }
  625.             fli_write_char(f, sc);
  626.             cc=1;
  627.             while ((linebuf[xc]==linebuf[xc+cc]) && ((xc+cc)<fli_header->width) && (cc<120)) {
  628.                 cc++;
  629.             }
  630.             if (cc>2) {
  631.                 bc++;
  632.                 fli_write_char(f, (cc-1)^0xFF);
  633.                 fli_write_char(f, linebuf[xc]);
  634.                 xc+=cc;
  635.             } else {
  636.                 tc=0;
  637.                 do {
  638.                     sc=0;
  639.                     while ((linebuf[tc+xc+sc]==old_linebuf[tc+xc+sc]) && ((tc+xc+sc)<fli_header->width) && (sc<5)) {
  640.                         sc++;
  641.                     }
  642.                     cc=1;
  643.                     while ((linebuf[tc+xc]==linebuf[tc+xc+cc]) && ((tc+xc+cc)<fli_header->width) && (cc<10)) {
  644.                         cc++;
  645.                     }
  646.                     tc++;
  647.                 } while ((tc<120) && (cc<9) && (sc<4) && ((xc+tc)<fli_header->width));
  648.                 bc++;
  649.                 fli_write_char(f, tc);
  650.                 fwrite(linebuf+xc, tc, 1, f);
  651.                 xc+=tc;
  652.             }
  653.         }
  654.         lineend=ftell(f); 
  655.         fseek(f, linepos, SEEK_SET);
  656.         fli_write_char(f, bc);
  657.         fseek(f, lineend, SEEK_SET);
  658.     }
  659.  
  660.     chunk.size=ftell(f)-chunkpos;
  661.     chunk.magic=FLI_LC;
  662.  
  663.     fseek(f, chunkpos, SEEK_SET);
  664.     fli_write_long(f, chunk.size);
  665.     fli_write_short(f, chunk.magic);
  666.     
  667.     if (chunk.size & 1) chunk.size++;
  668.     fseek(f,chunkpos+chunk.size,SEEK_SET);
  669. }
  670.  
  671.  
  672. /*
  673.  * This is an enhanced version of the old delta-compression used by
  674.  * the autodesk animator pro. It's word-oriented, and allows to skip
  675.  * larger parts of the image. This chunk is used in FLC files.
  676.  */
  677. void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
  678. {
  679.     unsigned short yc, lc, numline;
  680.     unsigned char *pos;
  681.     memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
  682.     yc=0;
  683.     numline = fli_read_short(f);
  684.     for (lc=0; lc < numline; lc++) {
  685.         unsigned short xc, pc, pcnt, lpf, lpn;
  686.         pc=fli_read_short(f);
  687.         lpf=0; lpn=0;
  688.         while (pc & 0x8000) {
  689.             if (pc & 0x4000) {
  690.                 yc+=-(signed short)pc;
  691.             } else {
  692.                 lpf=1;lpn=pc&0xFF;
  693.             }
  694.             pc=fli_read_short(f);
  695.         }
  696.         xc=0;
  697.         pos=framebuf+(fli_header->width * yc);
  698.         for (pcnt=pc; pcnt>0; pcnt--) {
  699.             unsigned short ps,skip;
  700.             skip=fli_read_char(f);
  701.             ps=fli_read_char(f);
  702.             xc+=skip;
  703.             if (ps & 0x80) {
  704.                 unsigned char v1,v2;
  705.                 ps=-(signed char)ps;
  706.                 v1=fli_read_char(f);
  707.                 v2=fli_read_char(f);
  708.                 while (ps>0) {
  709.                     pos[xc++]=v1;
  710.                     pos[xc++]=v2;
  711.                     ps--;
  712.                 }
  713.             } else {
  714.                 fread(&(pos[xc]), ps, 2, f);
  715.                 xc+=ps << 1;
  716.             }
  717.         }
  718.         if (lpf) pos[xc]=lpn;
  719.         yc++;
  720.     } 
  721. }
  722.