home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $Id: termSaveILBM.c,v 1.3 92/08/18 16:13:02 olsen Sta Locker: olsen $
- ** $Revision: 1.3 $
- ** $Date: 92/08/18 16:13:02 $
- **
- ** Support routines for saving IFF-ILBM files
- **
- ** Copyright ⌐ 1985-1992 by Jim Kent & Olaf `Olsen' Barthel
- */
-
- #include "termGlobal.h"
-
- /* This is basically Jim Kent's IFF-ILBM writer. Changes I made:
- *
- * - Put all support files into a single file.
- * - Added iffparse.library function calls.
- * - Added the CAMG chunk and implemented 32 bit viewmode IDs.
- * - Wrote a small routine to save the data.
- * - Added the ANNO version chunk.
- * - Added pixel aspect calculation routines.
- * - Changed the way the original source code was indented and
- * the names of some variables.
- */
-
- /* A bitmap header. */
-
- struct BitMapHeader
- {
- UWORD w,h; /* raster width & height in pixels */
- UWORD x,y; /* position for this image */
- UBYTE nPlanes; /* # source bitplanes */
- UBYTE masking; /* masking technique */
- UBYTE compression; /* compression algoithm */
- UBYTE pad1; /* UNUSED. For consistency, put 0 here.*/
- UWORD transparentColor; /* transparent "color number" */
- UBYTE xAspect,yAspect; /* aspect ratio, a rational number x/y */
- WORD pageWidth,pageHeight; /* source "page" size in pixels */
- };
-
- /* Compression status. */
-
- #define DUMP 0
- #define RUN 1
-
- /* Run length encoding constants. */
-
- #define MINRUN 3
- #define MAXRUN 128
- #define MAXDAT 128
-
- /* Size of the IFF write cache. */
-
- #define IFF_SIZE 4096
-
- /* Cache and cache index. */
-
- STATIC UBYTE IFFBuffer[IFF_SIZE];
- STATIC WORD IFFSize;
-
- /* FlushIFF(struct IFFHandle *IFFHandle):
- *
- * Flush the contents of the IFF write cache.
- */
-
- STATIC BYTE
- FlushIFF(struct IFFHandle *IFFHandle)
- {
- if(IFFSize)
- {
- if(WriteChunkBytes(IFFHandle,IFFBuffer,IFFSize) != IFFSize)
- {
- IFFSize = 0;
- return(FALSE);
- }
-
- IFFSize = 0;
- }
-
- return(TRUE);
- }
-
- /* PutIFF(struct IFFHandle *IFFHandle,UBYTE c):
- *
- * Send a single byte to the IFF write cache.
- */
-
- STATIC BYTE
- PutIFF(struct IFFHandle *IFFHandle,UBYTE c)
- {
- if(IFFSize == IFF_SIZE)
- if(!FlushIFF(IFFHandle))
- return(FALSE);
-
- IFFBuffer[IFFSize++] = c;
-
- return(TRUE);
- }
-
- /* WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,WORD Size):
- *
- * Write a buffer to the IFF cache.
- */
-
- STATIC BYTE
- WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,LONG Size)
- {
- LONG Len;
-
- while(Size)
- {
- if(IFFSize == IFF_SIZE)
- if(!FlushIFF(IFFHandle))
- return(FALSE);
-
- if((Len = Size) > IFF_SIZE - IFFSize)
- Len = IFF_SIZE - IFFSize;
-
- CopyMem(&Data[0],&IFFBuffer[IFFSize],Len);
-
- IFFSize += Len;
- Size -= Len;
-
- Data = &Data[Len];
- }
-
- return(TRUE);
- }
-
- STATIC LONG
- PackRow(struct IFFHandle *FileHandle,UBYTE *Source,LONG Size)
- {
- UBYTE c,LastByte = 0;
- BYTE CompMode = DUMP;
- WORD InBuf = 1; /* number of chars in buffer */
- WORD RunStart = 0; /* buffer index current run starts */
- LONG PutSize = 0;
-
- UBYTE LineBuf[MAXDAT * 3 / 2]; /* I think MAXDAT+1 would suffice */
-
- LineBuf[0] = LastByte = *Source++; /* so have valid LastByte */
- Size--; /* since one byte eaten. */
-
- for( ; Size ; --Size)
- {
- LineBuf[InBuf++] = c = *Source++;
-
- switch(CompMode)
- {
- case DUMP: /* If the buffer is full, write the length byte, then the data */
-
- if(InBuf > MAXDAT)
- {
- if(!PutIFF(FileHandle,InBuf-2))
- return(FALSE);
-
- if(!WriteIFF(FileHandle,LineBuf,InBuf-1))
- return(0);
-
- PutSize += InBuf;
-
- LineBuf[0] = c;
- InBuf = 1;
- RunStart = 0;
-
- break;
- }
-
- if(c == LastByte)
- {
- if(InBuf - RunStart >= MINRUN)
- {
- if(RunStart > 0)
- {
- if(!PutIFF(FileHandle,RunStart-1))
- return(FALSE);
-
- if(!WriteIFF(FileHandle,LineBuf,RunStart))
- return(0);
-
- PutSize += RunStart+1;
- }
-
- CompMode = RUN;
- }
- else
- {
- if(!RunStart)
- CompMode = RUN;
- }
-
- /* no dump in progress, so can't lose by making
- these 2 a run. */
- }
- else
- RunStart = InBuf - 1;/* first of run */
-
- break;
-
- case RUN: if((c != LastByte) ||(InBuf - RunStart > MAXRUN))
- {
- /* output run */
-
- if(!PutIFF(FileHandle,-(InBuf - RunStart - 2)))
- return(FALSE);
-
- if(!PutIFF(FileHandle,LastByte))
- return(FALSE);
-
- PutSize += 2;
-
- LineBuf[0] = c;
- InBuf = 1;
- RunStart = 0;
- CompMode = DUMP;
- }
-
- break;
- }
-
- LastByte = c;
- }
-
- switch(CompMode)
- {
- case DUMP: if(!PutIFF(FileHandle,InBuf-1))
- return(FALSE);
-
- if(!WriteIFF(FileHandle,LineBuf,InBuf))
- return(FALSE);
-
- PutSize += InBuf+1;
- break;
-
- case RUN: if(!PutIFF(FileHandle,-(InBuf - RunStart - 1)))
- return(FALSE);
-
- if(!PutIFF(FileHandle,LastByte))
- return(FALSE);
-
- PutSize += 2;
- break;
- }
-
- return(PutSize);
- }
-
- STATIC LONG
- PackBitMap(struct IFFHandle *FileHandle,struct BitMap *BitMap,LONG Height)
- {
- LONG i,j,RowLength,CompressedLength = 0,PlaneOffset = 0;
-
- for(i = 0 ; i < Height ; i++)
- {
- for(j = 0 ; j < BitMap -> Depth ; j++)
- {
- if(!(RowLength = PackRow(FileHandle,BitMap -> Planes[j] + PlaneOffset,BitMap -> BytesPerRow)))
- return(0);
-
- CompressedLength += RowLength;
- }
-
- PlaneOffset += BitMap -> BytesPerRow;
- }
-
- return(CompressedLength);
- }
-
- STATIC BYTE
- WriteILBM(UBYTE *FileName,UBYTE *Colours,struct BitMap *BitMap,LONG OffsetX,BYTE OffsetY,LONG Width,LONG Height,LONG Compressed,LONG PageWidth,LONG PageHeight,ULONG ViewModes)
- {
- struct IFFHandle *FileHandle;
- struct BitMapHeader BitMapHeader;
- LONG RowOffset;
- LONG i,j;
- WORD NumColours = 32;
- struct DisplayInfo DI;
- BYTE Success = TRUE;
-
- /* Calculate number of colours available. */
-
- if(BitMap)
- {
- if((NumColours = 1 << BitMap -> Depth) > 32)
- NumColours = 32;
-
- if(ViewModes & HAM)
- NumColours = 16;
- }
-
- if(FileHandle = AllocIFF())
- {
- if(FileHandle -> iff_Stream = Open(FileName,MODE_NEWFILE))
- {
- InitIFFasDOS(FileHandle);
-
- if(!OpenIFF(FileHandle,IFFF_WRITE))
- {
- /* Say its a FORM ILBM */
-
- if(!PushChunk(FileHandle,'ILBM','FORM',IFFSIZE_UNKNOWN))
- {
- /* Initialize the BitMapHeader to normal values */
-
- BitMapHeader . masking = 0;
- BitMapHeader . pad1 = 0;
- BitMapHeader . transparentColor = 0;
-
- if(Compressed)
- BitMapHeader . compression = 1;
- else
- BitMapHeader . compression = 0;
-
- BitMapHeader . pageWidth = PageWidth;
- BitMapHeader . pageHeight = PageHeight;
-
- /* Mask out all unwanted bits. */
-
- ViewModes &= ~(SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);
-
- /* Determine pixel aspect. */
-
- if(GetDisplayInfoData(NULL,(APTR)&DI,sizeof(struct DisplayInfo),DTAG_DISP,ViewModes))
- {
- BitMapHeader . xAspect = DI . Resolution . x;
- BitMapHeader . yAspect = DI . Resolution . y;
- }
- else
- {
- BitMapHeader . xAspect = 44;
- BitMapHeader . yAspect = (GfxBase -> DisplayFlags & PAL) ? 44 : 52;
-
- if(ViewModes & HIRES)
- BitMapHeader . xAspect >>= 1;
-
- if(ViewModes & LACE)
- BitMapHeader . yAspect >>= 1;
- }
-
- /* If it's not just a color map give the dimensions of rasters */
-
- if(BitMap)
- {
- BitMapHeader . w = Width;
- BitMapHeader . h = Height;
- BitMapHeader . nPlanes = BitMap -> Depth;
- BitMapHeader . x = OffsetX;
- BitMapHeader . y = OffsetY;
- }
-
- if(!PushChunk(FileHandle,0,'BMHD',sizeof(struct BitMapHeader)))
- {
- if(WriteChunkBytes(FileHandle,&BitMapHeader,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
- {
- if(!PopChunk(FileHandle))
- {
- if(!PushChunk(FileHandle,0,'ANNO',IFFSIZE_UNKNOWN))
- {
- extern UBYTE VersTag[];
-
- if(WriteChunkBytes(FileHandle,&VersTag[1],strlen(&VersTag[1])) != strlen(&VersTag[1]))
- Success = FALSE;
-
- if(PopChunk(FileHandle))
- Success = FALSE;
- }
-
- if(Success && !PushChunk(FileHandle,0,'CMAP',3 * NumColours))
- {
- if(WriteChunkBytes(FileHandle,Colours,3 * NumColours) == 3 * NumColours)
- {
- if(!PopChunk(FileHandle))
- {
- if(!PushChunk(FileHandle,0,'CAMG',sizeof(ULONG)))
- {
- if(WriteChunkBytes(FileHandle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
- {
- if(!PopChunk(FileHandle))
- {
- if(!PushChunk(FileHandle,0,'BODY',IFFSIZE_UNKNOWN))
- {
- if(Compressed)
- {
- if(!PackBitMap(FileHandle,BitMap,Height))
- Success = FALSE;
- else
- {
- if(!FlushIFF(FileHandle))
- Success = FALSE;
- }
- }
- else
- {
- i = Height;
- RowOffset = 0;
-
- while(--i >= 0 && Success)
- {
- for(j = 0 ; j < BitMap -> Depth ; j++)
- {
- if(WriteChunkBytes(FileHandle,BitMap -> Planes[j] + RowOffset,Height) != Height)
- {
- Success = FALSE;
- break;
- }
-
- RowOffset += BitMap -> BytesPerRow;
- }
- }
- }
-
- if(PopChunk(FileHandle))
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
-
- if(PopChunk(FileHandle))
- Success = FALSE;
- }
- else
- Success = FALSE;
- }
- else
- Success = FALSE;
-
- Close(FileHandle -> iff_Stream);
- }
- else
- Success = FALSE;
-
- FreeIFF(FileHandle);
- }
- else
- Success = FALSE;
-
- return(Success);
- }
-
- /* SaveRPort():
- *
- * Save the contents of a given RastPort to an IFF-ILBM
- * file, use iffparse.library to get the job done.
- */
-
- LONG
- SaveRPort(struct RastPort *RPort,struct ViewPort *VPort,LONG LeftEdge,LONG TopEdge,LONG Width,LONG Height,LONG ParentWidth,LONG ParentHeight,LONG Cookie,STRPTR Name)
- {
- UBYTE ColTable[32 * 3];
-
- struct BitMap DstMap,
- *SMap = RPort -> BitMap;
-
- LONG IFF_Result,
- r,g,b,
- i;
-
- UWORD TmpCol;
-
- BYTE ClosedWindow = FALSE;
-
- /* It is impossible to drag the packet window to
- * a place where it doesn't overlap the main window.
- * To avoid unpleasant effects we'll close it
- * and reopen it after saving the main window
- * contents.
- */
-
- if(PacketWindow)
- {
- ClosedWindow = TRUE;
-
- DeletePacketWindow(TRUE);
- }
-
- /* Reset buffer counter. */
-
- IFFSize = 0;
-
- /* Perform `cookie cut' (Note: in order to use the standard
- * IFF-ILBM save routines, we will use the cookie cut if a
- * interleaved screen bitmap is present).
- */
-
- if(LeftEdge || TopEdge || Cookie || InterleavedBitMap)
- {
- Cookie = TRUE;
-
- memset(&DstMap,0,sizeof(struct BitMap));
-
- InitBitMap(&DstMap,SMap -> Depth,Width,Height);
-
- for(i = 0 ; i < SMap -> Depth ; i++)
- {
- if(!(DstMap . Planes[i] = AllocRaster(Width,Height)))
- {
- IFF_Result = FALSE;
-
- goto Stop;
- }
- }
-
- BltBitMap(SMap,LeftEdge,TopEdge,&DstMap,0,0,Width,Height,0xC0,0xFF,NULL);
-
- SMap = &DstMap;
- }
-
- /* Convert the colours. */
-
- for(i = 0 ; i < 32 ; i++)
- {
- TmpCol = GetRGB4(VPort -> ColorMap,i)
-
- r = (TmpCol >> 8) & 0xF;
- g = (TmpCol >> 4) & 0xF;
- b = (TmpCol ) & 0xF;
-
- ColTable[i * 3 + 0] = (r << 4) | r;
- ColTable[i * 3 + 1] = (g << 4) | g;
- ColTable[i * 3 + 2] = (b << 4) | b;
- }
-
- /* Write the IFF-ILBM file. */
-
- IFF_Result = WriteILBM(Name,ColTable,SMap,LeftEdge,TopEdge,Width,Height,TRUE,ParentWidth,ParentHeight,GetVPModeID(VPort));
-
- /* Free the display cookie. */
-
- Stop: if(Cookie)
- {
- for(i = 0 ; i < DstMap . Depth ; i++)
- {
- if(DstMap . Planes[i])
- FreeRaster(DstMap . Planes[i],Width,Height);
- }
- }
-
- /* Delete truncated file or set the `not executable' bit
- * if successful.
- */
-
- if(!IFF_Result)
- DeleteFile(Name);
- else
- SetProtection(Name,FIBF_EXECUTE);
-
- /* Be a good boy and reopen the packet window. */
-
- if(ClosedWindow)
- CreatePacketWindow();
-
- return(IFF_Result);
- }
-