Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!rutgers!sri-spam!ames!amdahl!orandy From: orandy@amdahl.UUCP Newsgroups: comp.sys.amiga Subject: Initial posting of MandelVroom (7 of 8) Message-ID: <6769@amdahl.amdahl.com> Date: Tue, 19-May-87 21:25:33 EDT Article-I.D.: amdahl.6769 Posted: Tue May 19 21:25:33 1987 Date-Received: Thu, 21-May-87 03:02:46 EDT Organization: Amdahl Corporation, Sunnyvale, CA 94086 Lines: 753 Keywords: Amiga Developers IFF stuff for ILBMs # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # Makefile README SaveILBM.h iffw.c ilbmw.c packer.c saveilbm.c echo x - Makefile cat > "Makefile" << '//E*O*F Makefile//' OBJ = SaveILBM.o iffw.o ilbmw.o packer.o ScreenSave : $(OBJ) SaveILBM.p : SaveILBM.p cc +l SaveILBM.h +HSaveILBM.p SaveILBM.o : SaveILBM.c cc +l SaveILBM.c iffw.o : iffw.c cc +l iffw.c ilbmw.o : ilbmw.c cc +l ilbmw.c packer.o : packer.c cc +l packer.c //E*O*F Makefile// echo x - README cat > "README" << '//E*O*F README//' This direstory to contains files from the Amiga Delevopers IFF sources disk. MandelVroom uses these sources to save ILBM pictures. These sources are from Fish Disk 64. The IFF directory should contain: SaveILBM.c - code written by Carolyn Scheppner and hacked by me to save MandelVroom's screen as an ILBM. SaveILBM.h - include for SaveILBM.c packer.c - from the Amiga Developers IFF disk ilbmw.c - from the Amiga Developers IFF disk iffw.c - from the Amiga Developers IFF disk iff - a directory that contains the IFF disk include files //E*O*F README// echo x - SaveILBM.h cat > "SaveILBM.h" << '//E*O*F SaveILBM.h//' /*************************************************************************** * SaveILBM.h -- Save front screen as ILBM file * by Carolyn Scheppner CBM 10/86 * * modified by Kevin L. Clague for use in Mandelbrot * * Using IFF rtns by J.Morrison and S.Shaw of Electronic Arts * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "iff/ilbm.h" //E*O*F SaveILBM.h// echo x - iffw.c cat > "iffw.c" << '//E*O*F iffw.c//' /*----------------------------------------------------------------------* * IFFW.C Support routines for writing IFF-85 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. *----------------------------------------------------------------------*/ #include "iff/iff.h" #include "iff/gio.h" /* ---------- IFF Writer -----------------------------------------------*/ /* A macro to test if a chunk size is definite, i.e. not szNotYetKnown.*/ #define Known(size) ( (size) != szNotYetKnown ) /* Yet another weird macro to make the source code simpler...*/ #define IfIffp(expr) {if (iffp == IFF_OKAY) iffp = (expr);} /* ---------- OpenWIFF -------------------------------------------------*/ IFFP OpenWIFF(file, new0, limit) BPTR file; GroupContext *new0; LONG limit; { register GroupContext *new = new0; register IFFP iffp = IFF_OKAY; new->parent = NULL; new->clientFrame = NULL; new->file = file; new->position = 0; new->bound = limit; new->ckHdr.ckID = NULL_CHUNK; /* indicates no current chunk */ new->ckHdr.ckSize = new->bytesSoFar = 0; if (0 > Seek(file, 0, OFFSET_BEGINNING)) /* Go to start of the file.*/ iffp = DOS_ERROR; else if ( Known(limit) && IS_ODD(limit) ) iffp = CLIENT_ERROR; return(iffp); } /* ---------- StartWGroup ----------------------------------------------*/ IFFP StartWGroup(parent, groupType, groupSize, subtype, new) GroupContext *parent, *new; ID groupType, subtype; LONG groupSize; { register IFFP iffp; iffp = PutCkHdr(parent, groupType, groupSize); IfIffp( IFFWriteBytes(parent, (BYTE *)&subtype, sizeof(ID)) ); IfIffp( OpenWGroup(parent, new) ); return(iffp); } /* ---------- OpenWGroup -----------------------------------------------*/ IFFP OpenWGroup(parent0, new0) GroupContext *parent0, *new0; { register GroupContext *parent = parent0; register GroupContext *new = new0; register LONG ckEnd; register IFFP iffp = IFF_OKAY; new->parent = parent; new->clientFrame = parent->clientFrame; new->file = parent->file; new->position = parent->position; new->bound = parent->bound; new->ckHdr.ckID = NULL_CHUNK; new->ckHdr.ckSize = new->bytesSoFar = 0; if ( Known(parent->ckHdr.ckSize) ) { ckEnd = new->position + ChunkMoreBytes(parent); if ( new->bound == szNotYetKnown || new->bound > ckEnd ) new->bound = ckEnd; }; if ( parent->ckHdr.ckID == NULL_CHUNK || /* not currently writing a chunk*/ IS_ODD(new->position) || (Known(new->bound) && IS_ODD(new->bound)) ) iffp = CLIENT_ERROR; return(iffp); } /* ---------- CloseWGroup ----------------------------------------------*/ IFFP CloseWGroup(old0) GroupContext *old0; { register GroupContext *old = old0; IFFP iffp = IFF_OKAY; if ( old->ckHdr.ckID != NULL_CHUNK ) /* didn't close the last chunk */ iffp = CLIENT_ERROR; else if ( old->parent == NULL ) { /* top level file context */ if (GWriteFlush(old->file) < 0) iffp = DOS_ERROR; } else { /* update parent context */ old->parent->bytesSoFar += old->position - old->parent->position; old->parent->position = old->position; }; return(iffp); } /* ---------- EndWGroup ------------------------------------------------*/ IFFP EndWGroup(old) GroupContext *old; { register GroupContext *parent = old->parent; register IFFP iffp; iffp = CloseWGroup(old); IfIffp( PutCkEnd(parent) ); return(iffp); } /* ---------- PutCk ----------------------------------------------------*/ IFFP PutCk(context, ckID, ckSize, data) GroupContext *context; ID ckID; LONG ckSize; BYTE *data; { register IFFP iffp = IFF_OKAY; if ( ckSize == szNotYetKnown ) iffp = CLIENT_ERROR; IfIffp( PutCkHdr(context, ckID, ckSize) ); IfIffp( IFFWriteBytes(context, data, ckSize) ); IfIffp( PutCkEnd(context) ); return(iffp); } /* ---------- PutCkHdr -------------------------------------------------*/ IFFP PutCkHdr(context0, ckID, ckSize) GroupContext *context0; ID ckID; LONG ckSize; { register GroupContext *context = context0; LONG minPSize = sizeof(ChunkHeader); /* physical chunk >= minPSize bytes*/ /* CLIENT_ERROR if we're already inside a chunk or asked to write * other than one FORM, LIST, or CAT at the top level of a file */ /* Also, non-positive ID values are illegal and used for error codes.*/ /* (We could check for other illegal IDs...)*/ if ( context->ckHdr.ckID != NULL_CHUNK || ckID <= 0 ) return(CLIENT_ERROR); else if (context->parent == NULL) { switch (ckID) { case FORM: case LIST: case CAT: break; default: return(CLIENT_ERROR); } if (context->position != 0) return(CLIENT_ERROR); } if ( Known(ckSize) ) { if ( ckSize < 0 ) return(CLIENT_ERROR); minPSize += ckSize; }; if ( Known(context->bound) && context->position + minPSize > context->bound ) return(CLIENT_ERROR); context->ckHdr.ckID = ckID; context->ckHdr.ckSize = ckSize; context->bytesSoFar = 0; if (0 > GWrite(context->file, (BYTE *)&context->ckHdr, sizeof(ChunkHeader)) ) return(DOS_ERROR); context->position += sizeof(ChunkHeader); return(IFF_OKAY); } /* ---------- IFFWriteBytes ---------------------------------------------*/ IFFP IFFWriteBytes(context0, data, nBytes) GroupContext *context0; BYTE *data; LONG nBytes; { register GroupContext *context = context0; if ( context->ckHdr.ckID == NULL_CHUNK || /* not in a chunk */ nBytes < 0 || /* negative nBytes */ (Known(context->bound) && /* overflow context */ context->position + nBytes > context->bound) || (Known(context->ckHdr.ckSize) && /* overflow chunk */ context->bytesSoFar + nBytes > context->ckHdr.ckSize) ) return(CLIENT_ERROR); if (0 > GWrite(context->file, data, nBytes)) return(DOS_ERROR); context->bytesSoFar += nBytes; context->position += nBytes; return(IFF_OKAY); } /* ---------- PutCkEnd -------------------------------------------------*/ IFFP PutCkEnd(context0) GroupContext *context0; { register GroupContext *context = context0; WORD zero = 0; /* padding source */ if ( context->ckHdr.ckID == NULL_CHUNK ) /* not in a chunk */ return(CLIENT_ERROR); if ( context->ckHdr.ckSize == szNotYetKnown ) { /* go back and set the chunk size to bytesSoFar */ if ( 0 > GSeek(context->file, -(context->bytesSoFar + sizeof(LONG)), OFFSET_CURRENT) || 0 > GWrite(context->file, (BYTE *)&context->bytesSoFar, sizeof(LONG)) || 0 > GSeek(context->file, context->bytesSoFar, OFFSET_CURRENT) ) return(DOS_ERROR); } else { /* make sure the client wrote as many bytes as planned */ if ( context->ckHdr.ckSize != context->bytesSoFar ) return(CLIENT_ERROR); }; /* Write a pad byte if needed to bring us up to an even boundary. * Since the context end must be even, and since we haven't * overwritten the context, if we're on an odd position there must * be room for a pad byte. */ if ( IS_ODD(context->bytesSoFar) ) { if ( 0 > GWrite(context->file, (BYTE *)&zero, 1) ) return(DOS_ERROR); context->position += 1; }; context->ckHdr.ckID = NULL_CHUNK; context->ckHdr.ckSize = context->bytesSoFar = 0; return(IFF_OKAY); } //E*O*F iffw.c// echo x - ilbmw.c cat > "ilbmw.c" << '//E*O*F ilbmw.c//' /*----------------------------------------------------------------------* * 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. *----------------------------------------------------------------------*/ #include "iff/packer.h" #include "iff/ilbm.h" /*---------- InitBMHdr -------------------------------------------------*/ IFFP InitBMHdr(bmHdr0, bitmap, masking, compression, transparentColor, pageWidth, pageHeight) BitMapHeader *bmHdr0; struct BitMap *bitmap; WORD masking; /* Masking */ WORD compression; /* Compression */ WORD transparentColor; /* UWORD */ WORD pageWidth, pageHeight; { register BitMapHeader *bmHdr = bmHdr0; register WORD rowBytes = bitmap->BytesPerRow; bmHdr->w = rowBytes << 3; bmHdr->h = bitmap->Rows; bmHdr->x = bmHdr->y = 0; /* Default position is (0,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(rowBytes) ? 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(context, bitmap, mask, bmHdr, buffer, bufsize) GroupContext *context; struct BitMap *bitmap; BYTE *mask; BitMapHeader *bmHdr; BYTE *buffer; LONG bufsize; { IFFP iffp; LONG rowBytes = bitmap->BytesPerRow; int dstDepth = bmHdr->nPlanes; Compression compression = bmHdr->compression; int planeCnt; /* number of bit planes including mask */ register int iPlane, iRow; register LONG packedRowBytes; BYTE *buf; BYTE *planes[MaxAmDepth + 1]; /* 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; /* Write out a BODY chunk header */ iffp = PutCkHdr(context, ID_BODY, szNotYetKnown); CheckIFFP(); /* Write out the BODY contents */ for (iRow = bmHdr->h; iRow > 0; iRow--) { for (iPlane = 0; iPlane < planeCnt; iPlane++) { /* Write next row.*/ if (compression == cmpNone) { iffp = IFFWriteBytes(context, planes[iPlane], rowBytes); planes[iPlane] += rowBytes; } /* Compress and write next row.*/ else { buf = buffer; packedRowBytes = PackRow(&planes[iPlane], &buf, rowBytes); iffp = IFFWriteBytes(context, buffer, packedRowBytes); } CheckIFFP(); } } /* Finish the chunk */ iffp = PutCkEnd(context); return(iffp); } //E*O*F ilbmw.c// echo x - packer.c cat > "packer.c" << '//E*O*F packer.c//' /*----------------------------------------------------------------------* * packer.c Convert data to "cmpByteRun1" run compression. 11/15/85 * * By Jerry Morrison and Steve Shaw, Electronic Arts. * This software is in the public domain. * * control bytes: * [0..127] : followed by n+1 bytes of data. * [-1..-127] : followed by byte to be repeated (-n)+1 times. * -128 : NOOP. * * This version for the Commodore-Amiga computer. *----------------------------------------------------------------------*/ #include "iff/packer.h" #define DUMP 0 #define RUN 1 #define MinRun 3 #define MaxRun 128 #define MaxDat 128 LONG putSize; #define GetByte() (*source++) #define PutByte(c) { *dest++ = (c); ++putSize; } char buf[256]; /* [TBD] should be 128? on stack?*/ BYTE *PutDump(dest, nn) BYTE *dest; int nn; { int i; PutByte(nn-1); for(i = 0; i < nn; i++) PutByte(buf[i]); return(dest); } BYTE *PutRun(dest, nn, cc) BYTE *dest; int nn, cc; { PutByte(-(nn-1)); PutByte(cc); return(dest); } #define OutDump(nn) dest = PutDump(dest, nn) #define OutRun(nn,cc) dest = PutRun(dest, nn, cc) /*----------- PackRow --------------------------------------------------*/ /* Given POINTERS TO POINTERS, packs one row, updating the source and destination pointers. RETURNs count of packed bytes.*/ LONG PackRow(pSource, pDest, rowSize) BYTE **pSource, **pDest; LONG rowSize; { BYTE *source, *dest; char c,lastc = '\0'; BOOL mode = DUMP; short nbuf = 0; /* number of chars in buffer */ short rstart = 0; /* buffer index current run starts */ source = *pSource; dest = *pDest; putSize = 0; buf[0] = lastc = c = GetByte(); /* so have valid lastc */ nbuf = 1; rowSize--; /* since one byte eaten.*/ for (; rowSize; --rowSize) { buf[nbuf++] = c = GetByte(); switch (mode) { case DUMP: /* If the buffer is full, write the length byte, then the data */ if (nbuf>MaxDat) { OutDump(nbuf-1); buf[0] = c; nbuf = 1; rstart = 0; break; } if (c == lastc) { if (nbuf-rstart >= MinRun) { if (rstart > 0) OutDump(rstart); mode = RUN; } else if (rstart == 0) mode = RUN; /* no dump in progress, so can't lose by making these 2 a run.*/ } else rstart = nbuf-1; /* first of run */ break; case RUN: if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) { /* output run */ OutRun(nbuf-1-rstart,lastc); buf[0] = c; nbuf = 1; rstart = 0; mode = DUMP; } break; } lastc = c; } switch (mode) { case DUMP: OutDump(nbuf); break; case RUN: OutRun(nbuf-rstart,lastc); break; } *pSource = source; *pDest = dest; return(putSize); } //E*O*F packer.c// echo x - saveilbm.c cat > "saveilbm.c" << '//E*O*F saveilbm.c//' /*************************************************************************** * SaveILBM.c -- Save screen as ILBM file * * Modified version of Carolyn Scheppner's ScreenSave program * * Using IFF rtns by J.Morrison and S.Shaw of Electronic Arts * ***************************************************************************/ #include "SaveILBM.h" /* CAMG Stuff */ typedef struct { ULONG ViewModes; } CamgChunk; #define PutCAMG(context, camg) \ PutCk(context, ID_CAMG, sizeof(CamgChunk),(BYTE *)camg) #define bufSize 512 extern struct IntuitionBase *IntuitionBase; extern struct Screen *screen; extern struct Window *MandWind; struct Screen *frontScreen; struct ViewPort *picViewPort; struct BitMap *picBitMap; WORD *picColorTable; ULONG picViewModes; /************************************************************************** * * Save the current screen as an ILBM file * *************************************************************************/ SaveILBM(FileName) char *FileName; { LONG file; IFFP iffp = NO_FILE; int l; WindowToFront(MandWind); if (!(file = Open(FileName, MODE_NEWFILE))) { printf("Can't open file %s\n",FileName); return(0); } Write(file,"x",1); /* 1.1 so Seek to beginning works ? */ frontScreen = screen; picViewPort = &( frontScreen->ViewPort ); picBitMap = (struct BitMap*)picViewPort->RasInfo->BitMap; picColorTable = (WORD *)picViewPort->ColorMap->ColorTable; picViewModes = (ULONG)picViewPort->Modes; iffp = PutPicture(file, picBitMap, picColorTable, picViewModes); Close(file); if (iffp == IFF_OKAY) { printf("Screen saved\n"); } printf("Done\n"); } /* SaveILBM */ /** PutPicture() *********************************************************** * * Put a picture into an IFF file. * This procedure calls PutAnILBM, passing in an location of <0, 0>, * a NULL mask, and a locally-allocated buffer. It also assumes you want to * write out all the bitplanes in the BitMap. * ***************************************************************************/ Point2D nullPoint = {0, 0}; IFFP PutPicture(file, bitmap, colorMap, viewmodes) LONG file; struct BitMap *bitmap; WORD *colorMap; ULONG viewmodes; { BYTE buffer[bufSize]; return( PutAnILBM(file, bitmap, NULL, colorMap, bitmap->Depth, viewmodes, &nullPoint, buffer, bufSize) ); } /** PutAnILBM() ************************************************************ * * Write an entire BitMap as a FORM ILBM in an IFF file. * This version works for any display mode (C. Scheppner). * * Normal return result is IFF_OKAY. * * The utility program IFFCheck would print the following outline of the * resulting file: * * FORM ILBM * BMHD * CAMG * CMAP * BODY (compressed) * ***************************************************************************/ #define CkErr(expression) {if (ifferr == IFF_OKAY) ifferr = (expression);} IFFP PutAnILBM(file, bitmap, mask, colorMap, depth, viewmodes, xy, buffer, bufsize) LONG file; struct BitMap *bitmap; BYTE *mask; WORD *colorMap; UBYTE depth; ULONG viewmodes; Point2D *xy; BYTE *buffer; LONG bufsize; { BitMapHeader bmHdr; CamgChunk camgChunk; GroupContext fileContext, formContext; IFFP ifferr; WORD pageWidth, pageHeight; pageWidth = (bitmap->BytesPerRow) << 3; pageHeight = bitmap->Rows; ifferr = InitBMHdr(&bmHdr, bitmap, mskNone, cmpByteRun1, 0, pageWidth, pageHeight); /* You could write an uncompressed image by passing cmpNone instead * of cmpByteRun1 to InitBMHdr. */ bmHdr.nPlanes = depth; /* This must be <= bitmap->Depth */ if (mask != NULL) bmHdr.masking = mskHasMask; bmHdr.x = xy->x; bmHdr.y = xy->y; camgChunk.ViewModes = viewmodes; CkErr( OpenWIFF(file, &fileContext, szNotYetKnown) ); CkErr(StartWGroup(&fileContext, FORM, szNotYetKnown, ID_ILBM, &formContext)); CkErr( PutBMHD(&formContext, &bmHdr) ); CkErr( PutCAMG(&formContext, &camgChunk) ); CkErr( PutCMAP(&formContext, colorMap, depth) ); CkErr( PutBODY(&formContext, bitmap, mask, &bmHdr, buffer, bufsize) ); CkErr( EndWGroup(&formContext) ); CkErr( CloseWGroup(&fileContext) ); return( ifferr ); } //E*O*F saveilbm.c// echo Possible errors detected by \'wc\' [hopefully none]: temp=/tmp/shar$$ trap "rm -f $temp; exit" 0 1 2 3 15 cat > $temp <<\!!! 18 40 375 Makefile 20 90 627 README 27 67 781 SaveILBM.h 220 879 8008 iffw.c 144 573 5172 ilbmw.c 110 400 3578 packer.c 152 470 4420 saveilbm.c 691 2519 22961 total !!! wc Makefile README SaveILBM.h iffw.c ilbmw.c packer.c saveilbm.c | sed 's=[^ ]*/==' | diff -b $temp - exit 0 -- UUCP: orandy@amdahl.amdahl.com or: {sun,decwrl,hplabs,pyramid,ihnp4,seismo,oliveb,cbosgd}!amdahl!orandy DDD: 408-737-5481 USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086 [ Any thoughts or opinions which may or may not have been expressed ] [ herein are my own. They are not necessarily those of my employer. ]