/* Auto: make */ IMPORT BPTR SnapFile; IMPORT BYTE TranspBuf[]; #define ID(a,b,c,d) ((a << 24L) | (b << 16L) | (c << 8L) | (d)) struct ckHdr { LONG ChunkName; LONG ChunkSize; }; struct BitMapHeader { UWORD w,h; WORD x,y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE pad1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; }; struct ckHdr FORM = { ID('F','O','R','M'), 0L }; LONG TYPE = ID('I','L','B','M'); struct ckHdr BMHD = { ID('B','M','H','D'), sizeof(struct BitMapHeader) }; struct BitMapHeader BMHdr = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct ckHdr CAMG = { ID('C','A','M','G'), 4L }; ULONG ViewMode = NULL; struct ckHdr CMAP = { ID('C','M','A','P'), 0L }; struct ckHdr BODY = { ID('B','O','D','Y'), 0L }; UBYTE *buf; WORD bufcnt; ULONG totalsize; WORD bumpmode; #define BUMP_CALC 1 #define BUMP_SAVE 2 WORD bump(cnt, dataptr, size) WORD cnt; UBYTE *dataptr; WORD size; { REGISTER LONG tsize = size; if (tsize) { totalsize += tsize + 1; /* Don't forget the count-byte */ } if (bumpmode == BUMP_CALC) { /* Just calculating? */ return 1; /* Don't do the save */ } if (bufcnt + tsize + 1 >= 4096 || tsize == 0) { if (Write(SnapFile, buf, (LONG)bufcnt) == -1L) { return 0; } bufcnt = 0; } buf[bufcnt++] = cnt; CopyMem((char *)dataptr, (char *)&buf[bufcnt], tsize); bufcnt += tsize; return 1; } ULONG WriteBody(BM) struct BitMap *BM; { WORD scanline, plane; REGISTER WORD bpr = BM->BytesPerRow; REGISTER WORD i, j; LONG offset = 0L; REGISTER UBYTE data; REGISTER UBYTE *bd; totalsize = 0L; if (!(buf = AllocMem(4096L, MEMF_PUBLIC))) { return NULL; } bufcnt = 0; for (scanline = 0; scanline < BM->Rows; ++scanline) { for (plane = 0; plane < BM->Depth; ++plane) { bd = BM->Planes[plane]+offset; i = 1; j = bpr - 1; data = bd[0]; while (j) { if (bd[i] == data) { /* Equal bytes? */ --i; /* First equal byte */ if (i > 0) { /* Old "random" data to save */ if (!bump((WORD)(i - 1), bd, i)) { return NULL; } } bd = &bd[i]; /* Start of equal bytes */ i = 2; /* 0 & 1 is equal */ --j; while (i < 128 && j && bd[i] == data) { ++i; --j; } if (!bump((WORD)-(i - 1), &bd[i - 1], 1)) { return NULL; } goto new_block; } else { /* Not equal. Check block range */ if (i == 128) { /* Block limit */ if (!bump((WORD)(i - 1), bd, i)) { return NULL; } new_block: bd = &bd[i]; /* Start new block */ i = 0; if (j == 0) { break; } } } /* Different byte or a new start */ data = bd[i]; /* New possible equal */ next_byte: ++i; --j; } if (i != 0) { /* Data to save */ if (!bump((WORD)(i - 1), bd, i)) { return NULL; } } } offset += BM->BytesPerRow; } if (!bump(0, NULL, 0)) { /* Flush any bytes left if the buffer */ return NULL; } FreeMem(buf, 4096L); return totalsize; } WORD SaveGS(GS) struct GfxSnap *GS; { ULONG BODYPos; UBYTE *oldtitle; oldtitle = GS->window->Title; SetWindowTitles(GS->window, "Saving...", NULL); bumpmode = BUMP_SAVE; BMHdr.w = GS->BM.BytesPerRow * 8; BMHdr.h = GS->height; BMHdr.x = BMHdr.y = 0; BMHdr.nPlanes = GS->depth; BMHdr.masking = 0; BMHdr.compression = 1; BMHdr.transparentColor = dectoint(TranspBuf); BMHdr.xAspect = BMHdr.xAspect = 1; BMHdr.pageWidth = GS->pagew; BMHdr.pageHeight = GS->pageh; ViewMode = GS->viewmode; CMAP.ChunkSize = (LONG)3 * (GS->viewmode & HAM ? 16 : 1L << GS->depth); if (Write(SnapFile, (char *)&FORM, (LONG)(sizeof(FORM) + sizeof(TYPE) + sizeof(BMHD) + sizeof(BMHdr) + sizeof(CAMG) + sizeof(ViewMode) + sizeof(CMAP))) == -1L) { return 0; } if (Write(SnapFile, (char *)&GS->rgb[0], CMAP.ChunkSize) == -1L) { return 0; } BODYPos = Seek(SnapFile, 0L, OFFSET_CURRENT); if (Write(SnapFile, (char *)&BODY, (LONG)sizeof(BODY)) == -1L) { return 0; } if (!(BODY.ChunkSize = WriteBody(&GS->BM))) { return 0; } FORM.ChunkSize = BODYPos - sizeof(FORM) + sizeof(BODY) + BODY.ChunkSize; if (FORM.ChunkSize & 1) { /* Odd size */ if (Write(SnapFile, "X", 1L) == -1L) { return 0; } ++FORM.ChunkSize; } Seek(SnapFile, 0L, OFFSET_BEGINNING); Write(SnapFile, (char *)&FORM, (LONG)sizeof(FORM)); Seek(SnapFile, BODYPos, OFFSET_BEGINNING); Write(SnapFile, (char *)&BODY, (LONG)sizeof(BODY)); SetWindowTitles(GS->window, oldtitle, NULL); return 1; }