Amiga IFF examples (2 of 2)

Mike Farren farren at well.UUCP
Sat Jan 11 07:54:30 AEST 1986


    This is the second of two postings containing the Electronic Arts
    public domain examples for the IFF file interchange format.  This
    posting contains examples of reading and writing ILBM (Interleaved
    BitMap) type IFF files.  These are the files used to represent
    graphics screens on the Amiga by such programs as EA's Deluxe Paint.
      The document describing the IFF formats will be included in the
    version 1.1 Rom Kernal Manual, which should be available soon.

******************************* CUT HERE! *******************************
#
#    This is a shell archive.  To unpack the files, delete everything
#    before "#!/bin/sh", and then pipe the body through the "sh" command.
#    This archive contains the following files:
#
#    ilbm.h - The header file for the ILBM programs
#    ilbmr.c - The ILBM read routines
#    ilbmw.c - The ILBM write routines
#    packer.h - The header file for the packer/unpacker routines
#    packer.c - The row packer routine
#    unpacker.c - The row unpacker routine
#    raw2ilbm.c - A program demonstrating the use of the ILBM routines
#    showilbm.c - Another ILBM demonstration program
#    showilbm.lnk - The linker file for showilbm
#
echo 'Start of ILBM files'
echo 'x - ilbm.h'
sed 's/^X//' > ilbm.h << '/'
X#ifndef ILBM_H
X#define ILBM_H
X/*----------------------------------------------------------------------*
X * ILBM.H  Definitions for InterLeaved BitMap raster image.    11/15/85
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X#ifndef EXEC_TYPES_H
X#include "exec/types.h"
X#endif
X
X#ifndef GRAPHICS_GFX_H
X#include "graphics/gfx.h"
X#endif
X
X#include "iff/iff.h"
X
X#define ID_ILBM MakeID('I','L','B','M')
X#define ID_BMHD MakeID('B','M','H','D')
X#define ID_CMAP MakeID('C','M','A','P')
X#define ID_GRAB MakeID('G','R','A','B')
X#define ID_DEST MakeID('D','E','S','T')
X#define ID_SPRT MakeID('S','P','R','T')
X#define ID_CAMG MakeID('C','A','M','G')
X#define ID_BODY MakeID('B','O','D','Y')
X
X/* ---------- BitMapHeader ---------------------------------------------*/
X
Xtypedef UBYTE Masking;          /* Choice of masking technique.*/
X#define mskNone                 0
X#define mskHasMask              1
X#define mskHasTransparentColor  2
X#define mskLasso                3
X
Xtypedef UBYTE Compression;      /* Choice of compression algorithm applied to
X     * each row of the source and mask planes. "cmpByteRun1" is the byte run
X     * encoding generated by Mac's PackBits. See Packer.h . */
X#define cmpNone      0
X#define cmpByteRun1  1
X
X/* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel
X * aspect ratio pixel_width/pixel_height.
X *
X * For the 4 Amiga display modes:
X *   320 x 200: 10/11  (these pixels are taller than they are wide)
X *   320 x 400: 20/11
X *   640 x 200:  5/11
X *   640 x 400: 10/11           */
X#define x320x200Aspect 10
X#define y320x200Aspect 11
X#define x320x400Aspect 20
X#define y320x400Aspect 11
X#define x640x200Aspect  5
X#define y640x200Aspect 11
X#define x640x400Aspect 10
X#define y640x400Aspect 11
X
X/* A BitMapHeader is stored in a BMHD chunk. */
Xtypedef struct {
X    UWORD w, h;                 /* raster width & height in pixels */
X    WORD  x, y;                 /* position for this image */
X    UBYTE nPlanes;              /* # source bitplanes */
X    Masking masking;            /* masking technique */
X    Compression compression;    /* compression algoithm */
X    UBYTE pad1;                 /* UNUSED.  For consistency, put 0 here.*/
X    UWORD transparentColor;     /* transparent "color number" */
X    UBYTE xAspect, yAspect;     /* aspect ratio, a rational number x/y */
X    WORD  pageWidth, pageHeight;  /* source "page" size in pixels */
X    } BitMapHeader;
X
X/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
X#define RowBytes(w)   (((w) + 15) >> 4 << 1)
X
X
X/* ---------- ColorRegister --------------------------------------------*/
X/* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */
Xtypedef struct {
X    UBYTE red, green, blue;   /* MUST be UBYTEs so ">> 4" won't sign extend.*/
X    } ColorRegister;
X
X/* Use this constant instead of sizeof(ColorRegister). */
X#define sizeofColorRegister  3
X
Xtypedef WORD Color4;    /* Amiga RAM version of a color-register,
X                         * with 4 bits each RGB in low 12 bits.*/
X
X/* Maximum number of bitplanes in RAM. Current Amiga max w/dual playfield. */
X#define MaxAmDepth 6
X
X/* ---------- Point2D --------------------------------------------------*/
X/* A Point2D is stored in a GRAB chunk. */
Xtypedef struct {
X    WORD x, y;          /* coordinates (pixels) */
X    } Point2D;
X
X/* ---------- DestMerge ------------------------------------------------*/
X/* A DestMerge is stored in a DEST chunk. */
Xtypedef struct {
X    UBYTE depth;        /* # bitplanes in the original source */
X    UBYTE pad1;         /* UNUSED; for consistency store 0 here */
X    UWORD planePick;    /* how to scatter source bitplanes into destination */
X    UWORD planeOnOff;   /* default bitplane data for planePick */
X    UWORD planeMask;    /* selects which bitplanes to store into */
X    } DestMerge;
X
X/* ---------- SpritePrecedence -----------------------------------------*/
X/* A SpritePrecedence is stored in a SPRT chunk. */
Xtypedef UWORD SpritePrecedence;
X
X/* ---------- Viewport Mode --------------------------------------------*/
X/* A Commodore Amiga ViewPort->Modes is stored in a CAMG chunk. */
X/* The chunk's content is declared as a LONG. */
X
X/* ---------- CRange ---------------------------------------------------*/
X/* A CRange is store in a CRNG chunk. */
Xtypedef struct {
X    WORD  pad1;         /* reserved for future use; store 0 here */
X    WORD  rate;         /* color cycling rate, 16384 = 60 steps/second */
X    WORD  active;       /* nonzero means color cycling is turned on */
X    UBYTE low, high;    /* lower and upper color registers selected */
X    } CRange;
X
X/* ---------- ILBM Writer Support Routines -----------------------------*/
X
X/* Note: Just call PutCk to write a BMHD, GRAB, DEST, SPRT, or CAMG
X * chunk. As below. */
X#define PutBMHD(context, bmHdr)  \
X    PutCk(context, ID_BMHD, sizeof(BitMapHeader), (BYTE *)bmHdr)
X#define PutGRAB(context, point2D)  \
X    PutCk(context, ID_GRAB, sizeof(Point2D), (BYTE *)point2D)
X#define PutDEST(context, destMerge)  \
X    PutCk(context, ID_DEST, sizeof(DestMerge), (BYTE *)destMerge)
X#define PutSPRT(context, spritePrec)  \
X    PutCk(context, ID_SPRT, sizeof(SpritePrecedence), (BYTE *)spritePrec)
X
X/* Initialize a BitMapHeader record for a full-BitMap ILBM picture.
X * This gets w, h, and nPlanes from the BitMap fields BytesPerRow, Rows, and
X * Depth. It assumes you want  w = bitmap->BytesPerRow * 8 .
X * CLIENT_ERROR if bitmap->BytesPerRow isn't even, as required by ILBM format.
X *
X * If (pageWidth, pageHeight) is (320, 200), (320, 400), (640, 200), or
X * (640, 400) this sets (xAspect, yAspect) based on those 4 Amiga display
X * modes. Otherwise, it sets them to (1, 1).
X *
X * After calling this, store directly into the BitMapHeader if you want to
X * override any settings, e.g. to make nPlanes smaller, to reduce w a little,
X * or to set a position (x, y) other than (0, 0).*/
Xextern IFFP InitBMHdr(BitMapHeader *, struct BitMap *,
X                  /*  bmHdr,          bitmap  */
X     int,     int,         int,              int,       int);
X /*  masking, compression, transparentColor, pageWidth, pageHeight  */
X /*  Masking, Compression, UWORD,            WORD,      WORD  */
X
X/* Output a CMAP chunk to an open FORM ILBM write context. */
Xextern IFFP PutCMAP(GroupContext *, WORD *,   UBYTE);
X                /*  context,        colorMap, depth  */
X
X/* This procedure outputs a BitMap as an ILBM's BODY chunk with
X * bitplane and mask data. Compressed if bmHdr->compression == cmpByteRun1.
X * If the "mask" argument isn't NULL, it merges in the mask plane, too.
X * (A fancier routine could write a rectangular portion of an image.)
X * This gets Planes (bitplane ptrs) from "bitmap".
X *
X * CLIENT_ERROR if bitmap->Rows != bmHdr->h, or if
X * bitmap->BytesPerRow != RowBytes(bmHdr->w), or if
X * bitmap->Depth < bmHdr->nPlanes, or if bmHdr->nPlanes > MaxAmDepth, or if
X * bufsize < MaxPackedSize(bitmap->BytesPerRow), or if
X * bmHdr->compression > cmpByteRun1. */
Xextern IFFP PutBODY(
X    GroupContext *, struct BitMap *, BYTE *, BitMapHeader *, BYTE *, LONG);
X    /*  context,           bitmap,   mask,   bmHdr,         buffer, bufsize */
X
X/* ---------- ILBM Reader Support Routines -----------------------------*/
X
X/* Note: Just call IFFReadBytes to read a BMHD, GRAB, DEST, SPRT, or CAMG
X * chunk. As below. */
X#define GetBMHD(context, bmHdr)  \
X    IFFReadBytes(context, (BYTE *)bmHdr, sizeof(BitMapHeader))
X#define GetGRAB(context, point2D)  \
X    IFFReadBytes(context, (BYTE *)point2D, sizeof(Point2D))
X#define GetDEST(context, destMerge)  \
X    IFFReadBytes(context, (BYTE *)destMerge, sizeof(DestMerge))
X#define GetSPRT(context, spritePrec)  \
X    IFFReadBytes(context, (BYTE *)spritePrec, sizeof(SpritePrecedence))
X
X/* Input a CMAP chunk from an open FORM ILBM read context.
X * This converts to an Amiga color map: 4 bits each of red, green, blue packed
X * into a 16 bit color register.
X * pNColorRegs is passed in as a pointer to a UBYTE variable that holds
X * the number of ColorRegisters the caller has space to hold. GetCMAP sets
X * that variable to the number of color registers actually read.*/
Xextern IFFP GetCMAP(GroupContext *, WORD *,   UBYTE *);
X                /*  context,        colorMap, pNColorRegs  */
X
X/* GetBODY can handle a file with up to 16 planes plus a mask.*/
X#define MaxSrcPlanes 16+1
X
X/* GetBODY reads an ILBM's BODY into a client's bitmap, de-interleaving and
X * decompressing.
X *
X * Caller should first compare bmHdr dimensions (rowWords, h, nPlanes) with
X * bitmap dimensions, and consider reallocating the bitmap.
X * If file has more bitplanes than bitmap, this reads first few planes (low
X * order ones). If bitmap has more bitplanes, the last few are untouched.
X * This reads the MIN(bmHdr->h, bitmap->Rows) rows, discarding the bottom
X * part of the source or leaving the bottom part of the bitmap untouched.
X *
X * GetBODY returns CLIENT_ERROR if asked to perform a conversion it doesn't
X * handle. It only understands compression algorithms cmpNone and cmpByteRun1.
X * The filed row width (# words) must agree with bitmap->BytesPerRow.
X *
X * Caller should use bmHdr.w; GetBODY only uses it to compute the row width
X * in words. Pixels to the right of bmHdr.w are not defined.
X *
X * [TBD] In the future, GetBODY could clip the stored image horizontally or
X * fill (with transparentColor) untouched parts of the destination bitmap.
X *
X * GetBODY stores the mask plane, if any, in the buffer pointed to by mask.
X * If mask == NULL, GetBODY will skip any mask plane. If
X * (bmHdr.masking != mskHasMask) GetBODY just leaves the caller's mask alone.
X *
X * GetBODY needs a buffer large enough for two compressed rows.
X * It returns CLIENT_ERROR if bufsize < 2 * MaxPackedSize(bmHdr.rowWords * 2).
X *
X * GetBODY can handle a file with up to MaxSrcPlanes planes. It returns
X * CLIENT_ERROR if the file has more. (Could be due to a bum file, though.)
X * If GetBODY fails, it might've modified the client's bitmap. Sorry.*/
Xextern IFFP GetBODY(
X    GroupContext *, struct BitMap *, BYTE *, BitMapHeader *, BYTE *, LONG);
X    /*  context,           bitmap,   mask,   bmHdr,         buffer, bufsize */
X
X/* [TBD] Add routine(s) to create masks when reading ILBMs whose
X * masking != mskHasMask. For mskNone, create a rectangular mask. For
X * mskHasTransparentColor, create a mask from transparentColor. For mskLasso,
X * create an "auto mask" by filling transparent color from the edges. */
X
X#endif
X
/
echo 'x - ilbmr.c'
sed 's/^X//' > ilbmr.c << '/'
X/*----------------------------------------------------------------------*
X * ILBMR.C  Support routines for reading ILBM files.           11/27/85
X * (IFF is Interchange Format File.)
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X#include "iff/packer.h"
X#include "iff/ilbm.h"
X
X
X/* ---------- GetCMAP ------------------------------------------------*/
X/* pNColorRegs is passed in as a pointer to the number of ColorRegisters
X * caller has space to hold.  GetCMAP sets to the number actually read.*/
XIFFP GetCMAP(ilbmContext, colorMap, pNColorRegs)
X      GroupContext *ilbmContext;  WORD *colorMap;  UBYTE *pNColorRegs;
X   {
X   register int nColorRegs;
X   register IFFP iffp;
X   ColorRegister colorReg;
X
X   nColorRegs = ilbmContext->ckHdr.ckSize / sizeofColorRegister;
X   if (*pNColorRegs < nColorRegs)   nColorRegs = *pNColorRegs;
X   *pNColorRegs = nColorRegs;   /* Set to the number actually there.*/
X
X   for ( ;  nColorRegs > 0;  --nColorRegs)  {
X      iffp = IFFReadBytes(ilbmContext, (BYTE *)&colorReg,sizeofColorRegister);
X      CheckIFFP();
X      *colorMap++ = ( ( colorReg.red   >> 4 ) << 8 ) |
X                    ( ( colorReg.green >> 4 ) << 4 ) |
X                    ( ( colorReg.blue  >> 4 )      );
X      }
X   return(IFF_OKAY);
X   }
X
X/*---------- GetBODY ---------------------------------------------------*/
X/* NOTE: This implementation could be a LOT faster if it used more of the
X * supplied buffer. It would make far fewer calls to IFFReadBytes (and
X * therefore to DOS Read) and to movemem. */
XIFFP GetBODY(context, bitmap, mask, bmHdr, buffer, bufsize)
X      GroupContext *context;  struct BitMap *bitmap;  BYTE *mask;
X      BitMapHeader *bmHdr;  BYTE *buffer;  LONG bufsize;
X   {
X   register IFFP iffp;
X   UBYTE srcPlaneCnt = bmHdr->nPlanes;   /* Haven't counted for mask plane yet*/
X   WORD srcRowBytes = RowBytes(bmHdr->w);
X   LONG bufRowBytes = MaxPackedSize(srcRowBytes);
X   int nRows = bmHdr->h;
X   Compression compression = bmHdr->compression;
X   register int iPlane, iRow, nEmpty;
X   register WORD nFilled;
X   BYTE *buf, *nullDest, *nullBuf, **pDest;
X   BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
X
X   if (compression > cmpByteRun1)
X      return(CLIENT_ERROR);
X
X   /* Complain if client asked for a conversion GetBODY doesn't handle.*/
X   if ( srcRowBytes  !=  bitmap->BytesPerRow  ||
X         bufsize < bufRowBytes * 2  ||
X         srcPlaneCnt > MaxSrcPlanes )
X      return(CLIENT_ERROR);
X
X   if (nRows > bitmap->Rows)
X      nRows = bitmap->Rows;
X
X   /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
X   for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
X      planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
X   for ( ;  iPlane < MaxSrcPlanes;  iPlane++)
X      planes[iPlane] = NULL;
X
X   /* Copy any mask plane ptr into corresponding "planes" slot.*/
X   if (bmHdr->masking == mskHasMask) {
X      if (mask != NULL)
X         planes[srcPlaneCnt] = mask;  /* If there are more srcPlanes than
X               * dstPlanes, there will be NULL plane-pointers before this.*/
X      else
X         planes[srcPlaneCnt] = NULL;  /* In case more dstPlanes than src.*/
X      srcPlaneCnt += 1;  /* Include mask plane in count.*/
X      }
X
X   /* Setup a sink for dummy destination of rows from unwanted planes.*/
X   nullDest = buffer;
X   buffer  += srcRowBytes;
X   bufsize -= srcRowBytes;
X
X   /* Read the BODY contents into client's bitmap.
X    * De-interleave planes and decompress rows.
X    * MODIFIES: Last iteration modifies bufsize.*/
X   buf = buffer + bufsize;  /* Buffer is currently empty.*/
X   for (iRow = nRows; iRow > 0; iRow--)  {
X      for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)  {
X
X         pDest = &planes[iPlane];
X
X         /* Establish a sink for any unwanted plane.*/
X         if (*pDest == NULL) {
X            nullBuf = nullDest;
X            pDest   = &nullBuf;
X            }
X
X         /* Read in at least enough bytes to uncompress next row.*/
X         nEmpty  = buf - buffer;          /* size of empty part of buffer.*/
X         nFilled = bufsize - nEmpty;      /* this part has data.*/
X         if (nFilled < bufRowBytes) {
X            /* Need to read more.*/
X
X            /* Move the existing data to the front of the buffer.*/
X            /* Now covers range buffer[0]..buffer[nFilled-1].*/
X            movmem(buf, buffer, nFilled);  /* Could be moving 0 bytes.*/
X
X            if (nEmpty > ChunkMoreBytes(context)) {
X               /* There aren't enough bytes left to fill the buffer.*/
X               nEmpty = ChunkMoreBytes(context);
X               bufsize = nFilled + nEmpty;  /* heh-heh */
X               }
X
X            /* Append new data to the existing data.*/
X            iffp = IFFReadBytes(context, &buffer[nFilled], nEmpty);
X            CheckIFFP();
X
X            buf     = buffer;
X            nFilled = bufsize;
X            nEmpty  = 0;
X            }
X
X         /* Copy uncompressed row to destination plane.*/
X         if (compression == cmpNone) {
X            if (nFilled < srcRowBytes)  return(BAD_FORM);
X            movmem(buf, *pDest, srcRowBytes);
X            buf    += srcRowBytes;
X            *pDest += srcRowBytes;
X            }
X         else
X         /* Decompress row to destination plane.*/
X            if ( UnPackRow(&buf, pDest, nFilled,  srcRowBytes) )
X                    /*  pSource, pDest, srcBytes, dstBytes  */
X               return(BAD_FORM);
X         }
X      }
X
X   return(IFF_OKAY);
X   }
X
/
echo 'x - ilbmw.c'
sed 's/^X//' > ilbmw.c << '/'
X/*----------------------------------------------------------------------*
X * ILBMW.C  Support routines for writing ILBM files.           11/15/85
X * (IFF is Interchange Format File.)
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X#include "iff/packer.h"
X#include "iff/ilbm.h"
X
X/*---------- InitBMHdr -------------------------------------------------*/
XIFFP InitBMHdr(bmHdr0, bitmap, masking, compression, transparentColor,
X            pageWidth, pageHeight)
X        BitMapHeader *bmHdr0;  struct BitMap *bitmap;
X        int masking, compression, transparentColor, pageWidth, pageHeight;
X        /*  Masking, Compression, UWORD,            WORD,      WORD  */
X    {
X    register BitMapHeader *bmHdr = bmHdr0;
X    register WORD rowBytes = bitmap->BytesPerRow;
X
X    bmHdr->w = rowBytes << 3;
X    bmHdr->h = bitmap->Rows;
X    bmHdr->x = bmHdr->y = 0;    /* Default position is (0,0).*/
X    bmHdr->nPlanes = bitmap->Depth;
X    bmHdr->masking = masking;
X    bmHdr->compression = compression;
X    bmHdr->pad1 = 0;
X    bmHdr->transparentColor = transparentColor;
X    bmHdr->xAspect = bmHdr->yAspect = 1;
X    bmHdr->pageWidth = pageWidth;
X    bmHdr->pageHeight = pageHeight;
X
X    if (pageWidth = 320)
X        switch (pageHeight) {
X            case 200: {bmHdr->xAspect = x320x200Aspect;
X                       bmHdr->yAspect = y320x200Aspect; break;}
X            case 400: {bmHdr->xAspect = x320x400Aspect;
X                       bmHdr->yAspect = y320x400Aspect; break;}
X            }
X    else if (pageWidth = 640)
X        switch (pageHeight) {
X            case 200: {bmHdr->xAspect = x640x200Aspect;
X                       bmHdr->yAspect = y640x200Aspect; break;}
X            case 400: {bmHdr->xAspect = x640x400Aspect;
X                       bmHdr->yAspect = y640x400Aspect; break;}
X            }
X
X    return( IS_ODD(rowBytes) ? CLIENT_ERROR : IFF_OKAY );
X    }
X
X/*---------- PutCMAP ---------------------------------------------------*/
XIFFP PutCMAP(context, colorMap, depth)
X      GroupContext *context;  WORD *colorMap;  UBYTE depth;
X   {
X   register LONG nColorRegs;
X   IFFP iffp;
X   ColorRegister colorReg;
X
X   if (depth > MaxAmDepth)   depth = MaxAmDepth;
X   nColorRegs = 1 << depth;
X
X   iffp = PutCkHdr(context, ID_CMAP, nColorRegs * sizeofColorRegister);
X   CheckIFFP();
X
X   for ( ;  nColorRegs;  --nColorRegs)  {
X      colorReg.red   = ( *colorMap >> 4 ) & 0xf0;
X      colorReg.green = ( *colorMap      ) & 0xf0;
X      colorReg.blue  = ( *colorMap << 4 ) & 0xf0;
X      iffp = IFFWriteBytes(context, (BYTE *)&colorReg, sizeofColorRegister);
X      CheckIFFP();
X      ++colorMap;
X      }
X
X   iffp = PutCkEnd(context);
X   return(iffp);
X   }
X
X/*---------- PutBODY ---------------------------------------------------*/
X/* NOTE: This implementation could be a LOT faster if it used more of the
X * supplied buffer. It would make far fewer calls to IFFWriteBytes (and
X * therefore to DOS Write). */
XIFFP PutBODY(context, bitmap, mask, bmHdr, buffer, bufsize)
X      GroupContext *context;  struct BitMap *bitmap;  BYTE *mask;
X      BitMapHeader *bmHdr;  BYTE *buffer;  LONG bufsize;
X   {
X   IFFP iffp;
X   LONG rowBytes = bitmap->BytesPerRow;
X   int dstDepth = bmHdr->nPlanes;
X   Compression compression = bmHdr->compression;
X   int planeCnt;                /* number of bit planes including mask */
X   register int iPlane, iRow;
X   register LONG packedRowBytes;
X   BYTE *buf;
X   BYTE *planes[MaxAmDepth + 1]; /* array of ptrs to planes & mask */
X
X   if ( bufsize < MaxPackedSize(rowBytes)  ||   /* Must buffer a comprsd row*/
X        compression > cmpByteRun1  ||           /* bad arg */
X        bitmap->Rows != bmHdr->h   ||           /* inconsistent */
X        rowBytes != RowBytes(bmHdr->w)  ||      /* inconsistent*/
X        bitmap->Depth < dstDepth   ||           /* inconsistent */
X        dstDepth > MaxAmDepth )                 /* too many for this routine*/
X      return(CLIENT_ERROR);
X
X   planeCnt = dstDepth + (mask == NULL ? 0 : 1);
X
X   /* Copy the ptrs to bit & mask planes into local array "planes" */
X   for (iPlane = 0; iPlane < dstDepth; iPlane++)
X      planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
X   if (mask != NULL)
X      planes[dstDepth] = mask;
X
X   /* Write out a BODY chunk header */
X   iffp = PutCkHdr(context, ID_BODY, szNotYetKnown);
X   CheckIFFP();
X
X   /* Write out the BODY contents */
X   for (iRow = bmHdr->h; iRow > 0; iRow--)  {
X      for (iPlane = 0; iPlane < planeCnt; iPlane++)  {
X
X         /* Write next row.*/
X         if (compression == cmpNone) {
X            iffp = IFFWriteBytes(context, planes[iPlane], rowBytes);
X            planes[iPlane] += rowBytes;
X            }
X
X         /* Compress and write next row.*/
X         else {
X            buf = buffer;
X            packedRowBytes = PackRow(&planes[iPlane], &buf, rowBytes);
X            iffp = IFFWriteBytes(context, buffer, packedRowBytes);
X            }
X
X         CheckIFFP();
X         }
X      }
X
X   /* Finish the chunk */
X   iffp = PutCkEnd(context);
X   return(iffp);
X   }
/
echo 'x - packer.h'
sed 's/^X//' > packer.h << '/'
X#ifndef PACKER_H
X#define PACKER_H
X/*----------------------------------------------------------------------*
X * PACKER.H  typedefs for Data-Compresser.                     11/15/85
X *
X * This module implements the run compression algorithm "cmpByteRun1"; the
X * same encoding generated by Mac's PackBits.
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X
X#ifndef EXEC_TYPES_H
X#include "exec/types.h"
X#endif
X
X/* This macro computes the worst case packed size of a "row" of bytes. */
X#define MaxPackedSize(rowSize)  ( (rowSize) + ( ((rowSize)+127) >> 7 ) )
X
X
X/* Given POINTERS to POINTER variables, packs one row, updating the source
X * and destination pointers. Returns the size in bytes of the packed row.
X * ASSUMES destination buffer is large enough for the packed row.
X * See MaxPackedSize. */
Xextern LONG PackRow(BYTE **, BYTE **, LONG);
X                /*  pSource, pDest,   rowSize */
X
X/* Given POINTERS to POINTER variables, unpacks one row, updating the source
X * and destination pointers until it produces dstBytes bytes (i.e., the
X * rowSize that went into PackRow).
X * If it would exceed the source's limit srcBytes or if a run would overrun
X * the destination buffer size dstBytes, it stops and returns TRUE.
X * Otherwise, it returns FALSE (no error). */
Xextern BOOL UnPackRow(BYTE **, BYTE **, WORD,     WORD);
X                  /*  pSource, pDest,   srcBytes, dstBytes  */
X
X#endif
X
/
echo 'x - packer.c'
sed 's/^X//' > packer.c << '/'
X/*----------------------------------------------------------------------*
X * packer.c Convert data to "cmpByteRun1" run compression.     11/15/85
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X *      control bytes:
X *       [0..127]   : followed by n+1 bytes of data.
X *       [-1..-127] : followed by byte to be repeated (-n)+1 times.
X *       -128       : NOOP.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X#include "iff/packer.h"
X
X#define DUMP    0
X#define RUN     1
X
X#define MinRun 3
X#define MaxRun 128
X#define MaxDat 128
X
XLONG putSize;
X#define GetByte()       (*source++)
X#define PutByte(c)      { *dest++ = (c);   ++putSize; }
X
Xchar buf[256];  /* [TBD] should be 128?  on stack?*/
X
XBYTE *PutDump(dest, nn)  BYTE *dest;  int nn; {
X        int i;
X
X        PutByte(nn-1);
X        for(i = 0;  i < nn;  i++)   PutByte(buf[i]);
X        return(dest);
X        }
X
XBYTE *PutRun(dest, nn, cc)   BYTE *dest;  int nn, cc; {
X        PutByte(-(nn-1));
X        PutByte(cc);
X        return(dest);
X        }
X
X#define OutDump(nn)   dest = PutDump(dest, nn)
X#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)
X
X/*----------- PackRow --------------------------------------------------*/
X/* Given POINTERS TO POINTERS, packs one row, updating the source and
X   destination pointers.  RETURNs count of packed bytes.*/
XLONG PackRow(pSource, pDest, rowSize)
X    BYTE **pSource, **pDest;   LONG rowSize; {
X    BYTE *source, *dest;
X    char c,lastc = '\0';
X    BOOL mode = DUMP;
X    short nbuf = 0;             /* number of chars in buffer */
X    short rstart = 0;           /* buffer index current run starts */
X
X    source = *pSource;
X    dest = *pDest;
X    putSize = 0;
X    buf[0] = lastc = c = GetByte();  /* so have valid lastc */
X    nbuf = 1;   rowSize--;      /* since one byte eaten.*/
X
X
X    for (;  rowSize;  --rowSize) {
X        buf[nbuf++] = c = GetByte();
X        switch (mode) {
X                case DUMP:
X                        /* If the buffer is full, write the length byte,
X                           then the data */
X                        if (nbuf>MaxDat) {
X                                OutDump(nbuf-1);
X                                buf[0] = c;
X                                nbuf = 1;   rstart = 0;
X                                break;
X                                }
X
X                        if (c == lastc) {
X                            if (nbuf-rstart >= MinRun) {
X                                if (rstart > 0) OutDump(rstart);
X                                mode = RUN;
X                                }
X                            else if (rstart == 0)
X                                mode = RUN;     /* no dump in progress,
X                                so can't lose by making these 2 a run.*/
X                            }
X                        else  rstart = nbuf-1;          /* first of run */
X                        break;
X
X                case RUN: if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) {
X                        /* output run */
X                        OutRun(nbuf-1-rstart,lastc);
X                        buf[0] = c;
X                        nbuf = 1; rstart = 0;
X                        mode = DUMP;
X                        }
X                        break;
X                }
X
X        lastc = c;
X        }
X
X    switch (mode) {
X        case DUMP: OutDump(nbuf); break;
X        case RUN: OutRun(nbuf-rstart,lastc); break;
X        }
X    *pSource = source;
X    *pDest = dest;
X    return(putSize);
X    }
X
/
echo 'x - unpacker.c'
sed 's/^X//' > unpacker.c << '/'
X/*----------------------------------------------------------------------*
X * unpacker.c Convert data from "cmpByteRun1" run compression. 11/15/85
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X *      control bytes:
X *       [0..127]   : followed by n+1 bytes of data.
X *       [-1..-127] : followed by byte to be repeated (-n)+1 times.
X *       -128       : NOOP.
X *
X * This version for the Commodore-Amiga computer.
X *----------------------------------------------------------------------*/
X#include "iff/packer.h"
X
X
X/*----------- UnPackRow ------------------------------------------------*/
X
X#define UGetByte()      (*source++)
X#define UPutByte(c)     (*dest++ = (c))
X
X/* Given POINTERS to POINTER variables, unpacks one row, updating the source
X * and destination pointers until it produces dstBytes bytes. */
XBOOL UnPackRow(pSource, pDest, srcBytes0, dstBytes0)
X        BYTE **pSource, **pDest;  WORD srcBytes0, dstBytes0; {
X    register BYTE *source = *pSource;
X    register BYTE *dest   = *pDest;
X    register WORD n;
X    register BYTE c;
X    register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
X    BOOL error = TRUE;  /* assume error until we make it through the loop */
X    WORD minus128 = -128;  /* get the compiler to generate a CMP.W */
X
X    while( dstBytes > 0 )  {
X        if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
X        n = UGetByte();
X
X        if (n >= 0) {
X            n += 1;
X            if ( (srcBytes -= n) < 0 )  goto ErrorExit;
X            if ( (dstBytes -= n) < 0 )  goto ErrorExit;
X            do {  UPutByte(UGetByte());  } while (--n > 0);
X            }
X
X        else if (n != minus128) {
X            n = -n + 1;
X            if ( (srcBytes -= 1) < 0 )  goto ErrorExit;
X            if ( (dstBytes -= n) < 0 )  goto ErrorExit;
X            c = UGetByte();
X            do {  UPutByte(c);  } while (--n > 0);
X            }
X        }
X    error = FALSE;      /* success! */
X
X  ErrorExit:
X    *pSource = source;  *pDest = dest;
X    return(error);
X    }
X
/
echo 'x - raw2ilbm.c'
sed 's/^X//' > raw2ilbm.c << '/'
X/** Raw2ILBM.c **************************************************************
X *
X * Read an raw raster image file and write an IFF FORM ILBM file.  11/15/85.
X *
X * By Jerry Morrison and Steve Shaw, Electronic Arts.
X * This software is in the public domain.
X *
X * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF WRITER.
X *
X ****************************************************************************/
X#include "graphics/system.h"
X#include "iff/ilbm.h"
X
X/* Size of the buffer for PutBODY. */
X#define bufSize 512
X
X
X/** PutAnILBM() *************************************************************
X *
X * Write an entire BitMap as a FORM ILBM in an IFF file.
X * This procedure assumes the image is in the Amiga's 320 x 200 display mode.
X *
X * Normal return result is IFF_OKAY.
X *
X * The utility program IFFCheck would print the following outline of the
X * resulting file:
X *
X *   FORM ILBM
X *     BMHD
X *     CMAP
X *     BODY       (compressed)
X *
X ****************************************************************************/
X#define CkErr(expression)  {if (ifferr == IFF_OKAY) ifferr = (expression);}
X
XIFFP PutAnILBM(file, bitmap, mask, colorMap, depth, xy, buffer, bufsize)
X      LONG file;  struct BitMap *bitmap;  BYTE *mask;  WORD *colorMap;
X      UBYTE depth;  Point2D *xy;  BYTE *buffer;  LONG bufsize;
X   {
X   BitMapHeader bmHdr;
X   GroupContext fileContext, formContext;
X   IFFP ifferr;
X
X   ifferr = InitBMHdr(&bmHdr, bitmap, mskNone, cmpByteRun1, 0, 320, 200);
X        /* You could write an uncompressed image by passing cmpNone instead
X         * of cmpByteRun1 to InitBMHdr. */
X   bmHdr.nPlanes = depth;       /* This must be  <= bitmap->Depth */
X   if (mask != NULL) bmHdr.masking = mskHasMask;
X   bmHdr.x = xy->x;   bmHdr.y = xy->y;
X
X   CkErr( OpenWIFF(file, &fileContext, szNotYetKnown) );
X   CkErr(StartWGroup(&fileContext, FORM, szNotYetKnown, ID_ILBM, &formContext));
X
X   CkErr( PutBMHD(&formContext, &bmHdr) );
X   CkErr( PutCMAP(&formContext, colorMap, depth) );
X   CkErr( PutBODY(&formContext, bitmap, mask, &bmHdr, buffer, bufsize) );
X
X   CkErr( EndWGroup(&formContext) );
X   CkErr( CloseWGroup(&fileContext) );
X   return( ifferr );
X   }
X
X/** PutPicture() ************************************************************
X *
X * Put a picture into an IFF file.
X * This procedure calls PutAnILBM, passing in an <x, y> location of <0, 0>,
X * a NULL mask, and a locally-allocated buffer. It also assumes you want to
X * write out all the bitplanes in the BitMap.
X *
X ****************************************************************************/
XPoint2D nullPoint = {0, 0};
X
XIFFP PutPicture(file, bitmap, colorMap)
X      LONG file;  struct BitMap *bitmap;  WORD *colorMap;
X   {
X   BYTE buffer[bufSize];
X   return( PutAnILBM(file, bitmap, NULL,
X                     colorMap, bitmap->Depth, &nullPoint,
X                     buffer, bufSize) );
X   }
X
X/* [TBD] More to come. We need code to read a "raw" raster file into a BitMap
X * and code to handle file opening & closing, error msgs, etc. */
X
/
echo 'x - showilbm.c'
sed 's/^X//' > showilbm.c << '/'
X/** ShowILBM.c **************************************************************
X *
X * Read an ILBM raster image file and display it.  11/19/85.
X *
X * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
X * This software is in the public domain.
X *
X * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
X *
X * The IFF reader portion is essentially a recursive-descent parser.
X * This program will look into a CAT or LIST to find a FORM ILBM, but it
X * won't look inside another FORM type for a nested FORM ILBM.
X *
X * The display portion is specific to the Commodore Amiga computer.
X *
X * NOTE: This program displays an image, pauses, then exits. It doesn't
X * bother to switch you back to the CLI or workbench "screen", so type
X * Amiga-N when it's done.
X *
X ****************************************************************************/
X
X#include "graphics/system.h"
X#include "libraries/dos.h"
X#include "iff/ilbm.h"
X
X/* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
X#define EXDepth 5
X#define maxColorReg (1<<EXDepth)
X#define MIN(a,b) ((a)<(b)?(a):(b))
X
X#define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
X
X/* general usage pointers */
Xstruct GfxBase *GfxBase;
X
X/* Globals for displaying an image */
Xstruct RastPort rP;
Xstruct BitMap bitmap;
Xstruct RasInfo rasinfo;
Xstruct View v = {0};
Xstruct ViewPort vp = {0};
X
X/* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
X#define bufSz 512
X
X/* Message strings for IFFP codes. */
Xchar MsgOkay[]        = { "(IFF_OKAY) No FORM ILBM in the file." };
Xchar MsgEndMark[]     = { "(END_MARK) How did you get this message?" };
Xchar MsgDone[]        = { "(IFF_DONE) All done."};
Xchar MsgDos[]         = { "(DOS_ERROR) The DOS returned an error." };
Xchar MsgNot[]         = { "(NOT_IFF) Not an IFF file." };
Xchar MsgNoFile[]      = { "(NO_FILE) No such file found." };
Xchar MsgClientError[] = { "(CLIENT_ERROR) ShowILBM bug or insufficient RAM."};
Xchar MsgForm[]        = { "(BAD_FORM) A malformed FORM ILBM." };
Xchar MsgShort[]       = { "(SHORT_CHUNK) A malformed FORM ILBM." };
Xchar MsgBad[]         = { "(BAD_IFF) A mangled IFF file." };
X
X/* THESE MUST APPEAR IN RIGHT ORDER!! */
Xchar *IFFPMessages[-LAST_ERROR+1] = {
X    /*IFF_OKAY*/  MsgOkay,
X    /*END_MARK*/  MsgEndMark,
X    /*IFF_DONE*/  MsgDone,
X    /*DOS_ERROR*/ MsgDos,
X    /*NOT_IFF*/   MsgNot,
X    /*NO_FILE*/   MsgNoFile,
X    /*CLIENT_ERROR*/ MsgClientError,
X    /*BAD_FORM*/  MsgForm,
X    /*SHORT_CHUNK*/  MsgShort,
X    /*BAD_IFF*/   MsgBad
X    };
X
X/*------------ ILBM reader -----------------------------------------------*/
X/* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
X * We allocate one of these on the stack for every LIST or FORM encountered
X * in the file and use it to hold BMHD & CMAP properties. We also allocate
X * an initial one for the whole file.
X * We allocate a new GroupContext (and initialize it by OpenRIFF or
X * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
X * just a context for reading (nested) chunks.
X *
X * If we were to scan the entire example file outlined below:
X *    reading          proc(s)                new               new
X *
X * --whole file--   ReadPicture+ReadIFF   GroupContext        ILBMFrame
X * CAT              ReadICat                GroupContext
X *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
X *     PROP ILBM    GetPrILBM                   GroupContext
X *       CMAP       GetCMAP
X *       BMHD       GetBMHD
X *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
X *       BODY       GetBODY
X *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
X *       BODY       GetBODY
X *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
X */
Xtypedef struct {
X   ClientFrame clientFrame;
X   UBYTE foundBMHD;
X   UBYTE nColorRegs;
X   BitMapHeader bmHdr;
X   Color4 colorMap[maxColorReg];
X   /* If you want to read any other property chunks, e.g. GRAB or CAMG, add
X    * fields to this record to store them. */
X   } ILBMFrame;
X
X
X/* NOTE: For a simple version of this program, set Fancy to 0.
X * That'll compile a program that skips all LISTs and PROPs in the input
X * file. It will look in CATs for FORMs ILBM. That's suitable for most uses.
X *
X * For a fancy version that handles LISTs and PROPs, set Fancy to 1. */
X#define Fancy  0
X
X
X/** DisplayPic() ************************************************************
X *
X * Interface to Amiga graphics ROM routines.
X *
X ****************************************************************************/
XDisplayPic(ptilbmFrame)  ILBMFrame *ptilbmFrame;  {
X    int i;
X    struct View *oldView = GfxBase->ActiView;   /* so we can restore it */
X
X    InitView(&v);
X    InitVPort(&vp);
X    v.ViewPort = &vp;
X    InitRastPort(&rP);
X    rP.BitMap = &bitmap;
X    rasinfo.BitMap = &bitmap;
X
X    /* Always show the upper left-hand corner of this picture. */
X    rasinfo.RxOffset = 0;
X    rasinfo.RyOffset = 0;
X
X    vp.DWidth = ptilbmFrame->bmHdr.pageWidth;   /* Physical display WIDTH */
X    vp.DHeight = ptilbmFrame->bmHdr.pageHeight; /* Display height */
X
X#if 0
X    /* Specify where on screen to put the ViewPort. */
X    vp.DxOffset = ptilbmFrame->bmHdr.x;
X    vp.DyOffset = ptilbmFrame->bmHdr.y;
X#else
X    /* Always display it in upper left corner of screen.*/
X#endif
X
X    if (ptilbmFrame->bmHdr.pageWidth <= 320)
X        vp.Modes = 0;
X    else vp.Modes = HIRES;
X    if (ptilbmFrame->bmHdr.pageHeight > 200) {
X        v.Modes |= LACE;
X        vp.Modes |= LACE;
X        }
X    vp.RasInfo = &rasinfo;
X    MakeVPort(&v,&vp);
X    MrgCop(&v);
X    LoadView(&v);       /* show the picture */
X    WaitBlit();
X    WaitTOF();
X    LoadRGB4(&vp, ptilbmFrame->colorMap, ptilbmFrame->nColorRegs);
X
X    for (i = 0; i < 5*60; ++i)  WaitTOF();      /* Delay 5 seconds. */
X
X    LoadView(oldView);  /* switch back to old view */
X    }
X
X/** GetFoILBM() *************************************************************
X *
X * Called via ReadPicture to handle every FORM encountered in an IFF file.
X * Reads FORMs ILBM and skips all others.
X * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
X * finds no BODY or if it has no BMHD to decode the BODY.
X *
X * Once we find a BODY chunk, we'll allocate the BitMap and read the image.
X *
X ****************************************************************************/
XIFFP GetFoILBM(parent)  GroupContext *parent;  {
X   /*compilerBug register*/ IFFP iffp;
X   GroupContext formContext;
X   ILBMFrame ilbmFrame;         /* only used for non-clientFrame fields.*/
X   register int i;
X   int plsize;  /* Plane size in bytes. */
X   int nPlanes; /* number of planes in our display image */
X   BYTE buffer[bufSz];
X
X   if (parent->subtype != ID_ILBM)
X      return(IFF_OKAY); /* just continue scaning the file */
X
X   ilbmFrame = *(ILBMFrame *)parent->clientFrame;
X   iffp = OpenRGroup(parent, &formContext);
X   CheckIFFP();
X
X   do switch (iffp = GetFChunkHdr(&formContext)) {
X      case ID_BMHD: {
X        ilbmFrame.foundBMHD = TRUE;
X        iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
X        break; }
X      case ID_CMAP: {
X        ilbmFrame.nColorRegs = maxColorReg;  /* we have room for this many */
X        iffp = GetCMAP(
X           &formContext, (WORD *)&ilbmFrame.colorMap, &ilbmFrame.nColorRegs);
X        break; }
X      case ID_BODY: {
X         if (!ilbmFrame.foundBMHD)  return(BAD_FORM);   /* No BMHD chunk! */
X
X         nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth);
X         InitBitMap(
X            &bitmap,
X            nPlanes,
X            ilbmFrame.bmHdr.w,
X            ilbmFrame.bmHdr.h);
X         plsize = RowBytes(ilbmFrame.bmHdr.w) * ilbmFrame.bmHdr.h;
X         if (bitmap.Planes[0] =
X                (PLANEPTR)AllocMem(nPlanes * plsize, MEMF_CHIP))
X            {
X            for (i = 1; i < nPlanes; i++)
X                bitmap.Planes[i] = (PLANEPTR) bitmap.Planes[0] + plsize*i;
X            iffp = GetBODY(
X                &formContext,
X                &bitmap,
X                NULL,
X                &ilbmFrame.bmHdr,
X                buffer,
X                bufSz);
X            if (iffp == IFF_OKAY) iffp = IFF_DONE;      /* Eureka */
X            }
X         else
X            iffp = CLIENT_ERROR;        /* not enough RAM for the bitmap */
X         break; }
X      case END_MARK: { iffp = BAD_FORM; break; } /* No BODY chunk! */
X      } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
X                          * subroutine returned IFF_OKAY (no errors).*/
X
X   if (iffp != IFF_DONE)  return(iffp);
X
X   /* If we get this far, there were no errors. */
X   CloseRGroup(&formContext);
X   DisplayPic(&ilbmFrame);
X   return(iffp);
X   }
X
X/** Notes on extending GetFoILBM ********************************************
X *
X * To read more kinds of chunks, just add clauses to the switch statement.
X * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
X * the switch statement in GetPrILBM, too.
X *
X * To read a FORM type that contains a variable number of data chunks--e.g.
X * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
X * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
X * case do whatever cleanup you need.
X *
X ****************************************************************************/
X
X/** GetPrILBM() *************************************************************
X *
X * Called via ReadPicture to handle every PROP encountered in an IFF file.
X * Reads PROPs ILBM and skips all others.
X *
X ****************************************************************************/
X#if Fancy
XIFFP GetPrILBM(parent)  GroupContext *parent;  {
X   /*compilerBug register*/ IFFP iffp;
X   GroupContext propContext;
X   ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
X
X   if (parent->subtype != ID_ILBM)
X      return(IFF_OKAY); /* just continue scaning the file */
X
X   iffp = OpenRGroup(parent, &propContext);
X   CheckIFFP();
X
X   do switch (iffp = GetPChunkHdr(&propContext)) {
X      case ID_BMHD: {
X        ilbmFrame->foundBMHD = TRUE;
X        iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
X        break; }
X      case ID_CMAP: {
X        ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */
X        iffp = GetCMAP(
X          &propContext, (WORD *)&ilbmFrame->colorMap, &ilbmFrame->nColorRegs);
X        break; }
X      } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
X                          * subroutine returned IFF_OKAY (no errors).*/
X
X   CloseRGroup(&propContext);
X   return(iffp == END_MARK ? IFF_OKAY : iffp);
X   }
X#endif
X
X/** GetLiILBM() *************************************************************
X *
X * Called via ReadPicture to handle every LIST encountered in an IFF file.
X *
X ****************************************************************************/
X#if Fancy
XIFFP GetLiILBM(parent)  GroupContext *parent;  {
X    ILBMFrame newFrame; /* allocate a new Frame */
X
X    newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
X
X    return( ReadIList(parent, (ClientFrame *)&newFrame) );
X    }
X#endif
X
X/** ReadPicture() ***********************************************************
X *
X * Read a picture from an IFF file, given a file handle open for reading.
X *
X ****************************************************************************/
XIFFP ReadPicture(file)  LONG file;  {
X   ILBMFrame iFrame;    /* Top level "client frame".*/
X   IFFP iffp = IFF_OKAY;
X
X#if Fancy
X   iFrame.clientFrame.getList = GetLiILBM;
X   iFrame.clientFrame.getProp = GetPrILBM;
X#else
X   iFrame.clientFrame.getList = SkipGroup;
X   iFrame.clientFrame.getProp = SkipGroup;
X#endif
X   iFrame.clientFrame.getForm = GetFoILBM;
X   iFrame.clientFrame.getCat  = ReadICat ;
X
X   /* Initialize the top-level client frame's property settings to the
X    * program-wide defaults. This example just records that we haven't read
X    * any BMHD property or CMAP color registers yet. For the color map, that
X    * means the default is to leave the machine's color registers alone.
X    * If you want to read a property like GRAB, init it here to (0, 0). */
X   iFrame.foundBMHD  = FALSE;
X   iFrame.nColorRegs = 0;
X
X   iffp = ReadIFF(file, (ClientFrame *)&iFrame);
X
X   Close(file);
X   return(iffp);
X   }
X
X/** main0() *****************************************************************/
Xvoid main0(filename)  char *filename;  {
X    LONG file;
X    IFFP iffp = NO_FILE;
X
X    /* load and display the picture */
X    if( !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) )
X        exit(0);
X    file = Open(filename, MODE_OLDFILE);
X    if (file)
X        iffp = ReadPicture(file);
X
X    printf(" %s\n", IFFPMessages[-iffp]);
X
X    /* cleanup */
X    if (bitmap.Planes[0])  {
X        FreeMem(bitmap.Planes[0],
X                bitmap.BytesPerRow * bitmap.Rows * bitmap.Depth);
X        FreeVPortCopLists(&vp);
X        FreeCprList(v.LOFCprList);
X        }
X    CloseLibrary(GfxBase);
X    }
X
X/** main() ******************************************************************/
Xvoid main(argc, argv)  int argc;  char **argv;  {
X    printf("Showing file '%s' ...", argv[1]);
X    if (argc < 2)
X        printf("\nUsage: 'ShowILBM filename'");
X    else
X        main0(argv[1]);
X    printf("\n");
X    exit(0);
X    }
X
/
echo 'x - showilbm.lnk'
sed 's/^X//' > showilbm.lnk << '/'
XFROM startup.o,showilbm.o,ilbmr.o,unpacker.o,iffr.o
XTO showilbm
XLIBRARY lc.lib,amiga.lib
/
exit
------------
Have fun!

-- 
           Mike Farren
           uucp: {your favorite backbone site}!hplabs!well!farren
           Fido: Sci-Fido, Fidonode 125/84, (415)655-0667



More information about the Comp.sources.unix mailing list