/*----------------------------------------------------------------------*
 * ILBMW.C  Support routines for writing ILBM files.            1/23/86
 * (IFF is Interchange Format File.)
 *
 * By Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 * This version for the Commodore-Amiga computer.
 *----------------------------------------------------------------------*/
#define FDwAT
#include <iff/packer.h>
#include <iff/ilbm.h>
#include <intuition/intuition.h>

/*---------- InitBMHdr -------------------------------------------------*/
IFFP InitBMHdr(bmHdr0,bitmap,masking,compression,transparentColor,
               w,h,pageWidth,pageHeight)
BitMapHeader *bmHdr0;  struct BitMap *bitmap;
WORD masking;     /* Masking */
WORD compression;     /* Compression */
WORD transparentColor;   /* UWORD */
WORD pageWidth, pageHeight;
int w,h;{
   register BitMapHeader *bmHdr=bmHdr0;
   bmHdr->w=RowBytes(w)<<3;              /* even number of bytes */
   bmHdr->h=h;
   bmHdr->x=0;
   bmHdr->y=0;
   bmHdr->nPlanes=bitmap->Depth;
   bmHdr->masking=masking;
   bmHdr->compression=compression;
   bmHdr->pad1=0;
   bmHdr->transparentColor=transparentColor;
   bmHdr->xAspect=bmHdr->yAspect=1;
   bmHdr->pageWidth=pageWidth;
   bmHdr->pageHeight=pageHeight;
   if(pageWidth==320)
      switch(pageHeight){
         case 200: bmHdr->xAspect=x320x200Aspect;
                   bmHdr->yAspect=y320x200Aspect; break;
         case 400: bmHdr->xAspect=x320x400Aspect;
                   bmHdr->yAspect=y320x400Aspect; break;}
   else if(pageWidth==640)
      switch(pageHeight){
         case 200: bmHdr->xAspect=x640x200Aspect;
                   bmHdr->yAspect=y640x200Aspect; break;
         case 400: bmHdr->xAspect=x640x400Aspect;
                   bmHdr->yAspect=y640x400Aspect; break;}
   return(IS_ODD(w)?CLIENT_ERROR:IFF_OKAY);}

/*---------- PutCMAP ---------------------------------------------------*/
IFFP PutCMAP(context,colorMap,depth)   
GroupContext *context;
WORD *colorMap;
UBYTE depth;{
   register LONG nColorRegs;   
   IFFP iffp;
   ColorRegister colorReg;
   if(depth>MaxAmDepth)depth=MaxAmDepth;
   nColorRegs=1<<depth;
   iffp=PutCkHdr(context,ID_CMAP,nColorRegs*sizeofColorRegister);
   CheckIFFP();
   for(;nColorRegs;--nColorRegs){
      colorReg.red=(*colorMap>>4)&0xf0;
      colorReg.green=(*colorMap)&0xf0;
      colorReg.blue =(*colorMap<<4)&0xf0;
      iffp=IFFWriteBytes(context,(BYTE *)&colorReg,sizeofColorRegister);
      CheckIFFP();
      ++colorMap;}
   iffp=PutCkEnd(context);
   return(iffp);}

/*---------- PutBODY ---------------------------------------------------*/
/* NOTE: This implementation could be a LOT faster if it used more of the
 * supplied buffer. It would make far fewer calls to IFFWriteBytes (and
 * therefore to DOS Write). */

IFFP PutBODY(window,context,bitmap,mask,bmHdr,buffer,bufsize)
struct Window *window;
GroupContext *context;
struct BitMap *bitmap;
BYTE *mask;
BitMapHeader *bmHdr;
BYTE *buffer;
LONG bufsize;{         
   IFFP iffp;
   LONG rowBytes=bitmap->BytesPerRow,rstart,readrow,rb;
   int dstDepth=bmHdr->nPlanes;
   Compression compression=bmHdr->compression;
   int planeCnt;      /* number of bit planes including mask */
   register int iPlane,iRow,i,sh1,sh2,sh;
   register LONG packedRowBytes;
   BYTE *buf,*b;
   unsigned char buf1[80];
   BYTE *planes[MaxAmDepth + 1],*pl;   /* array of ptrs to planes & mask */
   if(bufsize<MaxPackedSize(rowBytes)||   /* Must buffer a comprsd row*/
        compression>cmpByteRun1||         /* bad arg */
/*      bitmap->Rows!=bmHdr->h||             inconsistent */
/*      rowBytes!=RowBytes(bmHdr->w)||       inconsistent*/
        bitmap->Depth<dstDepth||          /* inconsistent */
        dstDepth>MaxAmDepth)              /* too many for this routine*/
   return(CLIENT_ERROR);
   planeCnt=dstDepth+(mask==NULL?0:1);

/* Copy the ptrs to bit & mask planes into local array "planes" */

   for(iPlane=0;iPlane<dstDepth;iPlane++){
      planes[iPlane]=(BYTE *)bitmap->Planes[iPlane];}
   if(mask!=NULL)planes[dstDepth]=mask;

   readrow=RowBytes(bmHdr->w);
   rb=(readrow<<3)-bmHdr->w;
   rstart=(window->LeftEdge+bmHdr->x)>>3;
   sh=(window->LeftEdge+bmHdr->x)%8;
   sh2=rb-sh;
   if(sh2<0)sh2+=16;
   if(sh2<9)sh1=0;
   else {
      sh1=sh2-8; sh2=8;}

/* Write out a BODY chunk header */

   iffp=PutCkHdr(context,ID_BODY,szNotYetKnown);
   CheckIFFP();

/* Write out the BODY contents */

   for(iRow=0;iRow<bmHdr->h;iRow++){
      for(iPlane=0;iPlane<planeCnt;iPlane++){
         
/* Write next row.*/

         pl=planes[iPlane]+rowBytes*(iRow+window->TopEdge+bmHdr->y);
         for(i=0;i<readrow;i++)buf1[i]=pl[i+rstart];
         buf1[0]<<=sh; buf1[0]>>=sh;
         buf1[readrow-2]>>=sh1; buf1[readrow-2]<<=sh1;
         buf1[readrow-1]>>=sh2; buf1[readrow-1]<<=sh2;
         if(compression==cmpNone){
            iffp=IFFWriteBytes(context,buf1,readrow);}

/* Compress and write next row.*/

         else{
            buf=buffer; b=&buf1[0];
            packedRowBytes=PackRow(&b,&buf,readrow);
            iffp=IFFWriteBytes(context,buffer,packedRowBytes);}
         CheckIFFP();}}

/* Finish the chunk */

   iffp=PutCkEnd(context);
   return(iffp);}
