home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma01.dms / ma01.adf / wasp / src / readiff.c < prev    next >
C/C++ Source or Header  |  1991-12-28  |  16KB  |  701 lines

  1. /* wasp - Copyright 1991 by Steven Reiz
  2.  * see COPYING and wasp.c for further info
  3.  * readiff.c, 4/12/90 - 31/12/90,
  4.  * 5/5/91 - 2/6/91, 23/6/91, 9/7/91, 16/11/91,
  5.  * 8/12/91, 27/12/91
  6.  */
  7.  
  8. static char *sourcefile=__FILE__;
  9.  
  10. #include "wasp.h"
  11.  
  12. static u_long pos;
  13. static short seen_bmhd, seen_cmap, seen_sham, seen_camg, seen_body;
  14. static short laced_sham=0;    /* one sham entry per two lines in lace mode */
  15. static short dynamic=0;        /* dynamic sliced (CTBL iso SHAM chunk) */
  16. static u_long viewmodes=0;
  17. static struct bmhd_t {
  18.     u_short w, h;
  19.     short x, y;
  20.     u_char nplanes, masking, compression, pad;
  21.     u_short transpcol;
  22.     u_char xaspect, yaspect;
  23.     short pagew, pageh;
  24. } bmhd;
  25. #define mskNone            0
  26. #define mskHasMask        1
  27. #define mskHasTransparentColor    2
  28. #define mskLasso        3
  29. static u_short *cmap, *curcmap;
  30. static u_short *sham=NULL;
  31. static short nplanes, ncmap, nregs, nsham, directrrgb=0;
  32. static short mask_plane;
  33.  
  34.  
  35. read_iff(void)
  36. {
  37.     u_long id;
  38.  
  39.     cread(&id, (int)sizeof(id));
  40.     if (!isgroupid(id)) {
  41.         cseek_in(0L, 0);
  42.         return 0;
  43.     }
  44.     pos=sizeof(id);
  45.     seen_bmhd=seen_cmap=seen_sham=seen_camg=seen_body=0;
  46.     do_chunk(id);
  47.     if (!seen_bmhd)
  48.     error0(E0_FATAL, E1_IFF, E2_BMHD, E3_MISS_CHUNK);
  49.     if (!seen_body) {
  50.         if (!seen_camg) {
  51.         error0(E0_WARNING, E1_IFF, E2_CAMG, E3_MISS_CHUNK);
  52.             viewmodes=(nplanes==6 ? VM_HAM : 0);
  53.             seen_camg=1;
  54.         }
  55.         pos=sizeof(id);
  56.         cseek_in(pos, 0);
  57.         do_chunk(id);
  58.     }
  59.     if (!seen_body)
  60.     error0(E0_FATAL, E1_IFF, E2_BODY, E3_MISS_CHUNK);
  61.     free(cmap);
  62.     return 1;
  63. }
  64.  
  65.  
  66. char *
  67. idstr(unsigned long id)
  68. {
  69.     static char ids[5];
  70.  
  71.     *(u_long *)ids=id;
  72.     ids[4]='\0';
  73.     return ids;
  74. }
  75.  
  76.  
  77. void
  78. do_chunk(unsigned long id)
  79. {
  80.     u_long size, t, newpos;
  81.  
  82.     cread(&size, (int)sizeof(size));
  83.     size=(size+1) & -2;
  84.     pos+=sizeof(size);
  85.     if (isgroupid(id)) {
  86.         cread(&t, (int)sizeof(t));
  87.         pos+=sizeof(t);
  88.         if (size<0)
  89.         error0(E0_FATAL, E1_IFF, E2_FORMAT, E3_NEGGROUPSIZE);
  90.         newpos=pos+size-sizeof(t);
  91.         while (pos<newpos) {
  92.             u_long pid;
  93.     
  94.             cread(&pid, (int)sizeof(pid));
  95.             pos+=sizeof(pid);
  96.             if (!isvalid(pid))
  97.         error0(E0_FATAL, E1_IFF, E2_FORMAT, E3_INVALID_ID);
  98.             else
  99.                 do_chunk(pid);
  100.         }
  101.         if (pos>newpos)
  102.         error0(E0_FATAL, E1_IFF, E2_FORMAT, E3_GROUP2SMALL);
  103.     } else {
  104.         /* normal chunks */
  105.         if (id==id('B', 'M', 'H', 'D') && !seen_bmhd) {
  106.             seen_bmhd=1;
  107.             if (size!=sizeof(struct bmhd_t))
  108.         error0(E0_ERROR, E1_IFF, E2_BMHD, E3_WRONGCHUNKSZ);
  109.             cread(&bmhd, (int)sizeof(struct bmhd_t));
  110.         nplanes=bmhd.nplanes;
  111.             pos+=size;
  112.         } else if (id==id('C', 'A', 'M', 'G') && !seen_camg) {
  113.         int nrmodes;
  114.  
  115.             seen_camg=1;
  116.             if (size!=sizeof(viewmodes))
  117.         error0(E0_ERROR, E1_IFF, E2_CAMG, E3_WRONGCHUNKSZ);
  118.             cread(&viewmodes, (int)sizeof(viewmodes));
  119.         nrmodes=0;
  120.         if (viewmodes & VM_EHB)
  121.         ++nrmodes;
  122.         if (viewmodes & VM_HAM)
  123.         ++nrmodes;
  124.         if (viewmodes & VM_HIRES)
  125.         ++nrmodes;
  126.         if (nrmodes>1)
  127.         error0(E0_FATAL, E1_IFF, E2_CAMG, E3_CAMGMODES);
  128.             pos+=size;
  129.         } else if (id==id('C', 'M', 'A', 'P') && !seen_cmap) {
  130.             seen_cmap=1;
  131.             do_cmap(size);
  132.         } else if (id==id('S', 'H', 'A', 'M') && !seen_sham) {
  133.             seen_sham=1;
  134.             do_sham(size, 0);
  135.         } else if (id==id('C', 'T', 'B', 'L') && !seen_sham) {
  136.             seen_sham=1;
  137.         dynamic=1;
  138.             do_sham(size, 1);
  139.         } else if (id==id('B', 'O', 'D', 'Y') 
  140.          && !seen_body && seen_bmhd) {
  141.             seen_body=1;
  142.             do_body(size);
  143.     } else if (id==id('A', 'N', 'N', 'O')) {
  144.         do_anno(size);
  145.         } else { /* skip unknown chunks */
  146.         error2(E0_WARNING, E1_IFF, E2_FORMAT, E3_UNKNOWN_CHUNK, idstr(id), size);
  147.             cseek_in(size, 1);
  148.             pos+=size;
  149.         }
  150.     }
  151. }
  152.  
  153.  
  154. isgroupid(unsigned long id)
  155. {
  156.     return isgroupid2(id, id('F', 'O', 'R', 'M')) ||
  157.            isgroupid2(id, id('L', 'I', 'S', 'T')) ||
  158.            isgroupid2(id, id('C', 'A', 'T', ' ')) ||
  159.            id==id('P', 'R', 'O', 'P');
  160. }
  161.  
  162.  
  163. isgroupid2(unsigned long i, unsigned long i2)
  164. {
  165.     char c;
  166.  
  167.     c=i;
  168.     return i==i2 || ((i&0xffffff00L)==(i2&0xffffff00L) && c>='1' && c<='9');
  169. }
  170.  
  171.  
  172. isvalid(unsigned long id)
  173. {
  174.     char *p;
  175.     int i;
  176.  
  177.     for (p=(char *)&id, i=0; i<4; ++i)
  178.         if (*p<' ' || *p>'~')
  179.             break;
  180.         else
  181.             ++p;
  182.     return i>=4;
  183. }
  184.  
  185.  
  186. void
  187. do_anno(unsigned long size)
  188. {
  189.     short i;
  190.     char *anno;
  191.  
  192.     anno=Malloc(size+1);
  193.     cread(anno, (int)size);
  194.     anno[size]='\0';
  195.     for (i=0; i<size; ++i) {
  196.         if (i==size-1 && !anno[i])
  197.             break;
  198.         if (anno[i]<' ' || anno[i]>'~')
  199.             anno[i]='.';
  200.     }
  201.     printe("ANNO: %s\n", anno);
  202.     free(anno);
  203.     pos+=size;
  204. }
  205.  
  206.  
  207. void
  208. do_cmap(unsigned long size)
  209. {
  210.     u_char filergb[3];
  211.     short i;
  212.  
  213.     if (size%6)
  214.     error0(E0_FATAL, E1_IFF, E2_CMAP, E3_WRONGCHUNKSZ);
  215.     ncmap=size/sizeof(filergb);
  216.     cmap=Malloc(ncmap*sizeof(u_short));
  217.     for (i=0; i<ncmap; ++i) {
  218.         cread(filergb, (int)sizeof(filergb));
  219.         cmap[i]=((u_short)filergb[0]&0xf0)<<4 | filergb[1]&0xf0 | (u_long)filergb[2]>>4;
  220.     }
  221.     pos+=size;
  222. }
  223.  
  224.  
  225. void
  226. extend_cmap(void)
  227. {
  228.     u_short *newcmap, rgb;
  229.     u_char r, g, b;
  230.     short i;
  231.  
  232.     newcmap=Malloc(2*ncmap*sizeof(u_short));
  233.     for (i=0; i<ncmap; ++i) {
  234.         rgb=cmap[i];
  235.         newcmap[i]=rgb;
  236.         r=(rgb&0x0f00)>>9;
  237.         g=(rgb&0x00f0)>>5;
  238.         b=(rgb&0x000f)>>1;
  239.         newcmap[i+ncmap]=(r<<8)|(g<<4)|b;
  240.     }
  241.     free(cmap);
  242.     cmap=newcmap;
  243.     ncmap*=2;
  244. }
  245.  
  246.  
  247. void
  248. do_sham(unsigned long size, int is_ctbl)
  249. {
  250.     short i;
  251.  
  252.     pos+=size;
  253.     if (!is_ctbl) {
  254.         cread(&i, 2);
  255.         if (i)
  256.             error1(E0_WARNING, E1_IFF, E2_SHAM, E3_UNKNOWN_VERSION, (int)i);
  257.         size-=2;
  258.     }
  259.     sham=Malloc(size);
  260.     cread(sham, (int)size);
  261.     nsham=size/2;
  262.     for (i=0; i<nsham; ++i)
  263.         sham[i]&=0x0fff;
  264. }
  265.  
  266.  
  267. void
  268. do_body(unsigned long size)
  269. {
  270.     short y;
  271.  
  272.     xsz=bmhd.w;
  273.     ysz=bmhd.h;
  274.     nregs=1<<nplanes;
  275.     if (viewmodes & VM_HAM)
  276.     nregs=16;
  277.     if (bmhd.masking==mskHasMask) {
  278.     error0(E0_WARNING, E1_IFF, E2_FORMAT, E3_MASKING);
  279.     mask_plane=1;
  280.     } else
  281.     mask_plane=0;
  282.     if (bmhd.compression!=0 && bmhd.compression!=1)
  283.     error1(E0_FATAL, E1_IFF, E2_COMPRESSION, E3_UNKNOWN_VERSION, (int)bmhd.compression);
  284.     if (viewmodes & VM_HAM) {
  285.         if (ncmap!=nregs)
  286.         error1(E0_WARNING, E1_IFF, E2_HAM, E3_WRONG_NR_CREGS, (int)ncmap);
  287.     if (nplanes!=6)
  288.         error1(E0_FATAL, E1_IFF, E2_HAM, E3_WRONG_NR_PLANES, (int)nplanes);
  289.     } else if (viewmodes & VM_EHB) {
  290.     if (nplanes!=6)
  291.         error1(E0_FATAL, E1_IFF, E2_EHB, E3_WRONG_NR_PLANES, (int)nplanes);
  292.         extend_cmap();
  293.     } else if (!seen_cmap) {
  294.     directrrgb=1;
  295.     if (seen_camg)
  296.         error0(E0_ERROR, E1_IFF_RGB, E2_CAMG, E3_UNEXP_CHUNK);
  297.     if (sham)
  298.         error0(E0_ERROR, E1_IFF_RGB, E2_SHAM, E3_UNEXP_CHUNK);
  299.     if (nplanes<12 || nplanes%3)
  300.         error1(E0_FATAL, E1_IFF_RGB, E2_FORMAT, E3_WRONG_NR_PLANES, (int)nplanes);
  301.     } else {
  302.         if (ncmap!=(1<<nplanes))
  303.         error2(E0_FATAL, E1_IFF, E2_FORMAT, E3_CREGS_PLANES, (int)ncmap,
  304.          (int)nplanes);
  305.     }
  306.     if (sham) {
  307.         int i;
  308.  
  309.         if (viewmodes & VM_EHB)
  310.         error0(E0_FATAL, E1_IFF, E2_EHB, E3_SLICED_EHB);
  311.     i=ysz;
  312.         if ((viewmodes & VM_LACE) && nregs*i!=nsham) {
  313.             i=(ysz+1)/2;
  314.         laced_sham=1;
  315.     }
  316.         if (nregs*i!=nsham)
  317.         error2(E0_FATAL, E1_IFF, E2_SHAM, E3_NENTRIES, (int)nsham, nregs*i);
  318.     }
  319.     printe("IFF input; %ld x %ld, %d plane%s, ", xsz, ysz, (int)nplanes,
  320.      (nplanes==1 ? "" : "s"));
  321.     if (viewmodes & VM_LACE)
  322.     printe("interlaced ");
  323.     if (sham)
  324.     printe("%s%s ", (laced_sham ? "lace-" : ""),
  325.      (dynamic ? "dynamic" : "sliced"));
  326.     if (directrrgb)
  327.     printe("direct rgb\n");
  328.     else if (viewmodes & VM_EHB)
  329.     printe("ehb\n");
  330.     else if (viewmodes & VM_HAM)
  331.     printe("ham\n");
  332.     else if (viewmodes & VM_HIRES)
  333.     printe("hires\n");
  334.     else
  335.     printe("lores\n");
  336.     if (!outfilename)
  337.     exit(0);
  338.     rgb=Malloc(ysz*sizeof(u_short *));
  339.     for (y=0; y<ysz; ++y)
  340.         rgb[y]=Calloc(xsz*sizeof(u_short));
  341.     set_bodylimit(size);
  342.     if (directrrgb)
  343.     read_direct_body();
  344.     else
  345.     read_body();
  346.     check_bodylimit();
  347.     pos+=size;
  348.     erase_counter(NULL);
  349. }
  350.  
  351.  
  352. static u_long bodylimit, bodypos;
  353. #define RBBUFSZ 32760
  354. static u_char *conv;
  355.  
  356. void
  357. set_bodylimit(unsigned long size)
  358. {
  359.     bodylimit=size;
  360.     bodypos=0;
  361. }
  362.  
  363.  
  364. void
  365. check_bodylimit(void)
  366. {
  367.     if (bodypos!=bodylimit)
  368.     error0(E0_ERROR, E1_IFF, E2_BODY, E3_UNSPEC);
  369. }
  370.  
  371.  
  372. short
  373. nextbody(void *buf)
  374. {
  375.     int toread;
  376.  
  377.     toread=bodylimit-bodypos;
  378.     if (toread<=0) {
  379.     error1(E0_ERROR, E1_IFF, E2_BODY, E3_UNEXPEND, "chunk");
  380.     return 0;
  381.     }
  382.     if (toread>RBBUFSZ)
  383.         toread=RBBUFSZ;
  384.     cread_type=CREAD_NONFATAL;
  385.     cread(buf, toread);
  386.     cread_type=CREAD_STRICT;
  387.     if (cread_result<=0)
  388.     return 0;
  389.     if (cread_result!=toread)
  390.     toread=cread_result;
  391.     bodypos+=toread;
  392.     return (short)toread;
  393. }
  394.  
  395.  
  396.  
  397. void
  398. read_direct_body(void)
  399. {
  400.     short bufn, x, y, z, planei;
  401.     u_char *buf, *bufp;
  402.     char *row, *q, c;
  403.  
  404.     init_counter(0, (int)ysz, 10, "reading RGB IFF");
  405.     row=Malloc((nplanes+mask_plane)*((xsz+15)/16)*2+128);
  406.     buf=Malloc(RBBUFSZ);
  407.     bufn=0;
  408.     for (y=0; y<ysz; ++y) {
  409.         counter();
  410.         for (planei=0; planei<nplanes+mask_plane; ++planei) {
  411.             if (bmhd.compression) {
  412.                 x=(xsz+15)/16*2;
  413.                 q=row+planei*x;
  414.                 while (x>0) {
  415.             if (--bufn<0) {
  416.             bufn=nextbody(buf)-1;
  417.             if (bufn<0)
  418.                 goto quit_read_direct_body;
  419.             bufp=buf;
  420.             }
  421.             z= *bufp++;
  422.                     if (z<=127) {
  423.             x-=z;
  424.             --x;
  425.                         while (z>=0) {
  426.                 if (--bufn<0) {
  427.                 bufn=nextbody(buf)-1;
  428.                 if (bufn<0)
  429.                     goto quit_read_direct_body;
  430.                 bufp=buf;
  431.                 }
  432.                 *q++ = *bufp++;
  433.                             --z;
  434.                         }
  435.                     } else if (z==128) {
  436.                         /* do nothing */
  437.                     } else {
  438.             z=257-z;
  439.             x-=z;
  440.             if (--bufn<0) {
  441.                 bufn=nextbody(buf)-1;
  442.                 if (bufn<0)
  443.                 goto quit_read_direct_body;
  444.                 bufp=buf;
  445.             }
  446.             c= *bufp++;
  447.                         while (--z>=0)
  448.                             *q++ =c;
  449.                     }
  450.                 }
  451.                 if (x!=0)
  452.             error0(E0_ERROR, E1_IFF, E2_COMPRESSION, E3_ROWBOUND);
  453.             } else {
  454.                 for (x=(xsz+15)/16*2-1, q=row+planei*((xsz+15)/16*2); x>=0; --x) {
  455.             if (--bufn<0) {
  456.             bufn=nextbody(buf)-1;
  457.             if (bufn<0)
  458.                 goto quit_read_direct_body;
  459.             bufp=buf;
  460.             }
  461.             *q++ = *bufp++;
  462.         }
  463.             }
  464.         }
  465.     do_row_direct(y, (u_char *)row);
  466.     }
  467. quit_read_direct_body:
  468.     free(row);
  469.     free(buf);
  470. }
  471.  
  472.  
  473. void
  474. read_body(void)
  475. {
  476.     short bufn, x, y;
  477.     long lon;
  478.     short z;
  479.     u_char *buf, *bufp;
  480.     u_long *p, *q, *row;
  481.  
  482.     init_counter(0, (int)ysz, 20, "reading IFF");
  483.     if (sham)
  484.         curcmap=sham;
  485.     else
  486.         curcmap=cmap;
  487.     row=Malloc(8*(xsz+15)/16*2+128);
  488.     buf=Malloc(RBBUFSZ);
  489.     bufn=0;
  490.     conv=Malloc((nplanes+mask_plane)*256*8);
  491.     fill_conv();
  492.     for (y=0; y<ysz; ++y) {
  493.         counter();
  494.         for (lon=(long)conv; lon<(long)conv+(nplanes+mask_plane)*256*8; lon+=256*8) {
  495.             if (bmhd.compression) {
  496.                 x=(xsz+15)/16*2;
  497.                 q=row;
  498.                 while (x>0) {
  499.             if (--bufn<0) {
  500.             bufn=nextbody(buf)-1;
  501.             if (bufn<0)
  502.                 goto quit_read_body;
  503.             bufp=buf;
  504.             }
  505.             z= *bufp++;
  506.                     if (z<=127) {
  507.             x-=z;
  508.             --x;
  509.                         while (z>=0) {
  510.                 if (--bufn<0) {
  511.                 bufn=nextbody(buf)-1;
  512.                 if (bufn<0)
  513.                     goto quit_read_body;
  514.                 bufp=buf;
  515.                 }
  516.                             p=(u_long *)(lon+(*bufp++ <<3));
  517.                             if (lon==(long)conv) {
  518.                                 *q++ = *p++;
  519.                                 *q++ = *p;
  520.                             } else {
  521.                                 *q++ |= *p++;
  522.                                 *q++ |= *p;
  523.                             }
  524.                             --z;
  525.                         }
  526.                     } else if (z==128) {
  527.                         /* do nothing */
  528.                     } else {
  529.             z=257-z;
  530.             x-=z;
  531.             if (--bufn<0) {
  532.                 bufn=nextbody(buf)-1;
  533.                 if (bufn<0)
  534.                 goto quit_read_body;
  535.                 bufp=buf;
  536.             }
  537.                         p=(u_long *)(lon+(*bufp++ <<3));
  538.                         if (lon==(long)conv) {
  539.                             while (--z>=0) {
  540.                                 *q++ = *p++;
  541.                                 *q++ = *p;
  542.                                 --p;
  543.                             }
  544.                         } else {
  545.                             while (--z>=0) {
  546.                                 *q++ |= *p++;
  547.                                 *q++ |= *p;
  548.                                 --p;
  549.                             }
  550.                         }
  551.                     }
  552.                 }
  553.                 if (x!=0)
  554.             error0(E0_ERROR, E1_IFF, E2_COMPRESSION, E3_ROWBOUND);
  555.             } else {
  556.                 for (x=(xsz+15)/16*2-1, q=row; x>=0; --x) {
  557.             if (--bufn<0) {
  558.             bufn=nextbody(buf)-1;
  559.             if (bufn<0)
  560.                 goto quit_read_body;
  561.             bufp=buf;
  562.             }
  563.                     p=(u_long *)(lon+(*bufp++ <<3));
  564.                     if (lon==(long)conv) {
  565.                         *q++ = *p++;
  566.                         *q++ = *p;
  567.                     } else {
  568.                         *q++ |= *p++;
  569.                         *q++ |= *p;
  570.                     }
  571.                 }
  572.             }
  573.         }
  574.         if (viewmodes & VM_HAM)
  575.             do_row_ham(y, (u_char *)row);
  576.         else
  577.             do_row(y, (u_char *)row);
  578.         if (sham && (!laced_sham || !(y&1)))
  579.             curcmap+=nregs;
  580.     }
  581. quit_read_body:
  582.     free(conv);
  583.     free(row);
  584.     free(buf);
  585. }
  586.  
  587.  
  588. void
  589. fill_conv(void)
  590. {
  591.     u_char *powtab, *p;
  592.     short x, y;
  593.     char i;
  594.     short j;
  595.  
  596.     powtab=Malloc(8);
  597.     p=powtab;
  598.     for (i=1; i; i<<=1)
  599.         *p++ =i;
  600.     p=conv;
  601.     for (y=0; y<nplanes; ++y) {
  602.         for (x=0; x<256; ++x) {
  603.             for (j=128; j; j>>=1) {
  604.                 if (j&x)
  605.                     *p++ =powtab[y];
  606.                 else
  607.                     *p++ =0;
  608.             }
  609.         }
  610.     }
  611.     if (mask_plane) {
  612.         for (x=0; x<256; ++x)
  613.             for (j=128; j; j>>=1)
  614.                 *p++ =0;
  615.     }
  616.     free(powtab);
  617. }
  618.  
  619.  
  620. void
  621. do_row(short y, unsigned char *parrow)
  622. {
  623.     u_short *rgbrow;
  624.     u_char *row;
  625.     short x;
  626.  
  627.     rgbrow=rgb[y];
  628.     row=parrow;
  629.     for (x=xsz-1; x>=0; --x)
  630.         *rgbrow++ =curcmap[*row++];
  631. }
  632.  
  633.  
  634. void
  635. do_row_ham(short y, unsigned char *parrow)
  636. {
  637.     u_short *rgbrow;
  638.     u_char *row, pixel;
  639.     short x;
  640.     u_short curcolor;
  641.  
  642.     rgbrow=rgb[y];
  643.     row=parrow;
  644.     curcolor=curcmap[0];
  645.     x=xsz-1;
  646.     do {
  647.         pixel= *row++;
  648.         if (pixel&0x20) {
  649.             if (pixel&0x10) { /* modify green */
  650.                 curcolor=(curcolor&0x0f0f)|((pixel&0x0f)<<4);
  651.             } else {          /* modify red */
  652.                 curcolor=(curcolor&0x00ff)|((pixel&0x0f)<<8);
  653.             }
  654.         } else {
  655.             if (pixel&0x10) { /* modify blue */
  656.                 curcolor=(curcolor&0x0ff0)|(pixel&0x0f);
  657.             } else {          /* use curcmap */
  658.                 curcolor=curcmap[pixel];
  659.             }
  660.         }
  661.         *rgbrow++ =curcolor;
  662.     } while (--x>=0);
  663. }
  664.  
  665.  
  666. void
  667. do_row_direct(short y, unsigned char *inrow)
  668. {
  669.     u_short color, *dest;
  670.     long x, bytesperscan, plane0;
  671.     u_char *p, pmask, *plane1, *plane2, *plane3;
  672.  
  673.     dest=rgb[y];
  674.     bytesperscan=(xsz+7)/8;
  675.     plane0=nplanes/3*bytesperscan;
  676.     for (x=0; x<bytesperscan; ++x) {
  677.         plane1=inrow+x+plane0-bytesperscan;
  678.         plane2=plane1+plane0;
  679.         plane3=plane2+plane0;
  680.         for (pmask=128; pmask; pmask=(unsigned long)pmask>>1) {
  681.             color=0;
  682.             p=plane1;
  683.             if (*p & pmask)    color|=0x0800; p-=bytesperscan;
  684.             if (*p & pmask)    color|=0x0400; p-=bytesperscan;
  685.             if (*p & pmask)    color|=0x0200; p-=bytesperscan;
  686.             if (*p & pmask)    color|=0x0100;
  687.             p=plane2;
  688.             if (*p & pmask)    color|=0x0080; p-=bytesperscan;
  689.             if (*p & pmask)    color|=0x0040; p-=bytesperscan;
  690.             if (*p & pmask)    color|=0x0020; p-=bytesperscan;
  691.             if (*p & pmask)    color|=0x0010;
  692.             p=plane3;
  693.             if (*p & pmask)    color|=0x0008; p-=bytesperscan;
  694.             if (*p & pmask)    color|=0x0004; p-=bytesperscan;
  695.             if (*p & pmask)    color|=0x0002; p-=bytesperscan;
  696.             if (*p & pmask)    color|=0x0001;
  697.             *dest++ =color;
  698.         }
  699.     }
  700. }
  701.