/************** * TURBOMANDEL * **************/ /* IFF read/write */ #include #include #include #include #include #include struct iff_chunk { long iff_type, iff_length; }; struct form_chunk { long fc_type, fc_length, fc_subtype; }; struct BitMapHeader { UWORD w, h, x, y; UBYTE nPlanes, masking, compression, pad1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; }; struct ILBM_info { struct BitMapHeader header; struct BitMap bitmap; UBYTE cmap[96]; }; extern struct MandelChunk { ULONG XCoo[2], YCoo[2], XSide[2], YSide[2]; UWORD Iteration; UBYTE Calculation, Flags; SHORT TopPos[3], DecrStep[3], ColInt[3]; } MandChunk; read_iff (info, name, just_header) struct ILBM_info *info; char *name; int just_header; { UBYTE bool; FILE *file; struct form_chunk chunk; if ((file = fopen (name, "r") ) == 0) return (FALSE); if (fread (&chunk, sizeof (struct form_chunk), 1, file) != 1) { fclose (file); return (FALSE); } if (chunk.fc_type != 'FORM' || chunk.fc_subtype != 'ILBM') { fclose (file); return (FALSE); } bool = read_ilbm (file, info, chunk.fc_length - sizeof (chunk), just_header); fclose (file); return ((int)bool); } read_ilbm (file, info, length, just_header) FILE *file; struct ILBM_info *info; long length; int just_header; { struct iff_chunk chunk; long read_in = 0; int got_header = FALSE, got_cmap = FALSE; while (read_in < length) { if (fread (&chunk, sizeof (chunk), 1, file) != 1) return (FALSE); switch (chunk.iff_type) { case 'BMHD': if (fread (&info->header, sizeof(info->header), 1, file) != 1) return (FALSE); got_header = TRUE; break; case 'MANC': /* read mandel chunk */ if (fread (&MandChunk, sizeof(MandChunk), 1, file) != 1) return (FALSE); break; case 'CMAP': if (!got_header) return (FALSE); if (chunk.iff_length <= 96) { if (fread (info->cmap, (int)chunk.iff_length, 1, file) != 1) return (FALSE); } else { if (fread(info->cmap, 96, 1, file) != 1) return (FALSE); fseek (file, (long)chunk.iff_length - sizeof (3 * 32), 1); } got_cmap = TRUE; break; case 'BODY': if (!got_cmap || !got_header) return (FALSE); if (just_header) return (TRUE); return (read_body (file, info, chunk.iff_length)); default: fseek (file, (long)chunk.iff_length, 1); break; } read_in += chunk.iff_length + sizeof(chunk); } return (FALSE); } read_body (file, info, length) FILE *file; register struct ILBM_info *info; long length; { long i, j, plane_offset; if (info->header.compression != 0 && info->header.compression != 1) return (FALSE); plane_offset = 0; for (i = 0; i < info->bitmap.Rows; i++) { if (info->header.compression == 0) { for (j = 0; j < info->bitmap.Depth; j++) if (fread(info->bitmap.Planes[j] + plane_offset, info->bitmap.BytesPerRow, 1, file) != 1) return(FALSE); } else { register char *dest, value; register int so_far, count; for (j = 0; j < info->bitmap.Depth; j++) { so_far = info->bitmap.BytesPerRow; dest = (char *)info->bitmap.Planes[j] + plane_offset; while (so_far > 0) { value = getc (file); if (value > 0 && value != 128) { count = (int)value + 1; so_far -= count; if (fread (dest, count, 1, file) != 1) return (FALSE); dest += count; } else { count = (int)-value + 1; so_far -= count; value = getc (file); while (--count >= 0) *dest++ = value; } } if (so_far != 0) return (FALSE); } } plane_offset += info->bitmap.BytesPerRow; } return (TRUE); } #define DUMP 0 #define RUN 1 ULONG pack_row (source, dest, size) char *source, *dest; int size; { char c, lastc = 0, *olddest; short mode = DUMP, nbuf = 0, rstart = 0, i; char buf[128*3/2]; olddest = dest; buf[0] = lastc = *source++; nbuf = 1; size--; for (; size; --size) { buf[nbuf++] = c = *source++; if (mode == DUMP) { if (nbuf > 128) { *dest++ = nbuf - 2; for (i = 0; i < nbuf-1; i++) *dest++ = buf[i]; buf[0] = c; nbuf = 1; rstart = 0; } else if (c == lastc) { if (nbuf - rstart >= 3) { if (rstart > 0) { *dest++ = rstart - 1; for (i = 0; i < rstart; i++) *dest++ = buf[i]; } mode = RUN; } else if (rstart == 0) mode = RUN; } else rstart = nbuf - 1; } else { if ((c != lastc) || (nbuf - rstart > 128)) { *dest++ = - (nbuf - rstart - 2); *dest++ = lastc; buf[0] = c; nbuf = 1; rstart = 0; mode = DUMP; } } lastc = c; } if (mode == DUMP) { *dest++ = nbuf - 1; for (i = 0; i < nbuf; i++) *dest++ = buf[i]; } else { *dest++ = - nbuf + rstart + 1; *dest++ = lastc; } return ((ULONG)(dest - olddest)); } ULONG pack_bitmap (file, bm) FILE *file; struct BitMap *bm; { char packbuffer[256]; int i, j, row_length; ULONG compressed_length = 0, plane_offset = 0; for (i = 0; i < bm->Rows; i++) { for (j = 0; j < bm->Depth; j++) { row_length = pack_row (bm->Planes[j] + plane_offset, packbuffer, bm->BytesPerRow); if (file) if (fwrite(packbuffer, row_length, 1, file) != 1) return (0); compressed_length += row_length; } plane_offset += bm->BytesPerRow; } if (compressed_length & 1) { if (file) if (putc (0, file) == EOF) return(0); compressed_length++; } return (compressed_length); } int write_iff (name, colors, scr, compressed) char *name; UWORD *colors; struct Screen *scr; int compressed; { struct BitMap *bits; struct form_chunk chunk; struct iff_chunk ichunk; struct BitMapHeader header; UBYTE rgbcolors[96]; SHORT i, numcols, j, row_offset; ULONG bits_size, viewmodes; FILE *file; if ((file = fopen (name, "w") ) == 0) return(0); if (scr) { bits = &scr->BitMap; if ((numcols = (1 << bits->Depth)) > 32) numcols = 32; } else numcols = 32; chunk.fc_type = 'FORM'; chunk.fc_subtype = 'ILBM'; chunk.fc_length = 4 + 3 * sizeof (struct iff_chunk) + 12 + 62 + numcols * 3 + sizeof(struct BitMapHeader); if (scr) { if (compressed) { if ((bits_size = pack_bitmap (NULL, bits)) == 0) return(0); } else bits_size = bits->BytesPerRow * bits->Rows * bits->Depth; chunk.fc_length += bits_size; } if (fwrite (&chunk, sizeof(chunk), 1, file) != 1) return(0); ichunk.iff_type = 'BMHD'; ichunk.iff_length = sizeof(header); if (fwrite (&ichunk, sizeof(ichunk), 1, file) != 1) return(0); header.masking = header.pad1 = header.transparentColor = 0; header.compression = compressed; header.pageWidth = bits->BytesPerRow * 8; header.pageHeight = bits->Rows; header.xAspect = header.yAspect = 10; /* write bitmapheader */ if (scr) { header.w = bits->BytesPerRow * 8; header.h = bits->Rows; header.nPlanes = bits->Depth; header.x = header.y = 0; } if (fwrite (&header, sizeof(header), 1, file) != 1) return(0); /* write camg */ ichunk.iff_type = 'CAMG'; ichunk.iff_length = 4; if (fwrite (&ichunk, sizeof(ichunk), 1, file) != 1) return(0); viewmodes = (ULONG)scr->ViewPort.Modes; if (fwrite (&viewmodes, 4, 1, file) != 1) return(0); /* write cmap */ ichunk.iff_type = 'CMAP'; ichunk.iff_length = numcols * 3; if (fwrite (&ichunk, sizeof(ichunk), 1, file) != 1) return(0); for (i = 0; i < numcols; i++) { rgbcolors[3 * i] = (colors[i] & 0xf00) >> 4; rgbcolors[3 * i + 1] = (colors[i] & 0x0f0); rgbcolors[3 * i + 2] = (colors[i] & 0x00f) << 4; } if (fwrite (&rgbcolors[0], numcols * 3, 1, file) != 1) return(0); /* write mandel chunk */ ichunk.iff_type = 'MANC'; ichunk.iff_length = sizeof(MandChunk); if (fwrite (&ichunk, sizeof(ichunk), 1, file) != 1) return(0); if (fwrite (&MandChunk, sizeof(MandChunk), 1, file) != 1) return (0); if (scr) { ichunk.iff_type = 'BODY'; ichunk.iff_length = bits_size; if (fwrite(&ichunk, sizeof(ichunk), 1, file) != 1) return(0); if (compressed) { if (pack_bitmap(file, bits) == 0) return(0); } else { i = bits->Rows; row_offset = 0; while (--i >= 0) { for (j = 0; j < bits->Depth; j++) if (fwrite( bits->Planes[j]+row_offset, bits->BytesPerRow, 1, file) != 1) return(0); row_offset += bits->BytesPerRow; } } } fclose (file); return (1); }