/* common/lbmlib.c */ #include #include /* * ============================================================================ * LBM STUFF * ============================================================================ */ #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) #define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) bmhd_t bmhd; int Align(int l) { if (l & 1) return l + 1; return l; } /* * ================ * LBMRLEdecompress * Source must be evenly aligned! * ================ */ byte * LBMRLEDecompress(byte *source, byte *unpacked, int bpwidth) { int count; byte b, rept; count = 0; do { rept = *source++; if (rept > 0x80) { rept = (rept ^ 0xff) + 2; b = *source++; memset(unpacked, b, rept); unpacked += rept; } else if (rept < 0x80) { rept++; memcpy(unpacked, source, rept); unpacked += rept; source += rept; } else rept = 0; /* rept of 0x80 is NOP */ count += rept; } while (count < bpwidth); if (count > bpwidth) Error("Decompression exceeded width!\n"); return source; } #define BPLANESIZE 128 byte bitplanes[9][BPLANESIZE]; /* max size 1024 by 9 bit planes */ /* * ================= * MungeBitPlanes8 * This destroys the bit plane data! * ================= */ void MungeBitPlanes8(int width, byte *dest) { *dest = width; /* shut up the compiler warning */ Error("MungeBitPlanes8 not rewritten!"); #if 0 asm les di,[dest] asm mov si, -1 asm mov cx,[width] mungebyte:asm inc si asm mov dx, 8 mungebit:asm shl[BYTE PTR bitplanes + BPLANESIZE * 7 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 6 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 5 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 4 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 3 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 2 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 1 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 0 + si], 1 asm rcl al, 1 asm stosb asm dec cx asm jz done asm dec dx asm jnz mungebit asm jmp mungebyte done: #endif } void MungeBitPlanes4(int width, byte *dest) { *dest = width; /* shut up the compiler warning */ Error("MungeBitPlanes4 not rewritten!"); #if 0 asm les di,[dest] asm mov si, -1 asm mov cx,[width] mungebyte:asm inc si asm mov dx, 8 mungebit:asm xor al, al asm shl[BYTE PTR bitplanes + BPLANESIZE * 3 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 2 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 1 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 0 + si], 1 asm rcl al, 1 asm stosb asm dec cx asm jz done asm dec dx asm jnz mungebit asm jmp mungebyte done: #endif } void MungeBitPlanes2(int width, byte *dest) { *dest = width; /* shut up the compiler warning */ Error("MungeBitPlanes2 not rewritten!"); #if 0 asm les di,[dest] asm mov si, -1 asm mov cx,[width] mungebyte:asm inc si asm mov dx, 8 mungebit:asm xor al, al asm shl[BYTE PTR bitplanes + BPLANESIZE * 1 + si], 1 asm rcl al, 1 asm shl[BYTE PTR bitplanes + BPLANESIZE * 0 + si], 1 asm rcl al, 1 asm stosb asm dec cx asm jz done asm dec dx asm jnz mungebit asm jmp mungebyte done: #endif } void MungeBitPlanes1(int width, byte *dest) { *dest = width; /* shut up the compiler warning */ Error("MungeBitPlanes1 not rewritten!"); #if 0 asm les di,[dest] asm mov si, -1 asm mov cx,[width] mungebyte:asm inc si asm mov dx, 8 mungebit:asm xor al, al asm shl[BYTE PTR bitplanes + BPLANESIZE * 0 + si], 1 asm rcl al, 1 asm stosb asm dec cx asm jz done asm dec dx asm jnz mungebit asm jmp mungebyte done: #endif } /* * ================= * LoadLBM * ================= */ void LoadLBM(char *filename, byte **picture, byte **palette) { byte *LBMbuffer, *picbuffer, *cmapbuffer; int y, p, planes; byte *LBM_P, *LBMEND_P; byte *pic_p; byte *body_p; unsigned rowsize; int formtype, formlength; int chunktype, chunklength; void (*mungecall) (int, byte *); /* quiet compiler warnings */ picbuffer = NULL; cmapbuffer = NULL; mungecall = NULL; /* load the LBM */ LoadFile(filename, &LBMbuffer); /* parse the LBM header */ LBM_P = LBMbuffer; if (*(int *)LBMbuffer != LittleLong(FORMID)) Error("No FORM ID at start of file!\n"); LBM_P += 4; formlength = BigLong(*(int *)LBM_P); LBM_P += 4; LBMEND_P = LBM_P + Align(formlength); formtype = LittleLong(*(int *)LBM_P); if (formtype != ILBMID && formtype != PBMID) Error("Unrecognized form type: %c%c%c%c\n", formtype & 0xff, (formtype >> 8) & 0xff, (formtype >> 16) & 0xff, (formtype >> 24) & 0xff); LBM_P += 4; /* parse chunks */ while (LBM_P < LBMEND_P) { chunktype = LBM_P[0] + (LBM_P[1] << 8) + (LBM_P[2] << 16) + (LBM_P[3] << 24); LBM_P += 4; chunklength = LBM_P[3] + (LBM_P[2] << 8) + (LBM_P[1] << 16) + (LBM_P[0] << 24); LBM_P += 4; switch (chunktype) { case BMHDID: memcpy(&bmhd, LBM_P, sizeof(bmhd)); bmhd.w = BigShort(bmhd.w); bmhd.h = BigShort(bmhd.h); bmhd.x = BigShort(bmhd.x); bmhd.y = BigShort(bmhd.y); bmhd.pageWidth = BigShort(bmhd.pageWidth); bmhd.pageHeight = BigShort(bmhd.pageHeight); break; case CMAPID: cmapbuffer = malloc(768); memset(cmapbuffer, 0, 768); memcpy(cmapbuffer, LBM_P, chunklength); break; case BODYID: body_p = LBM_P; pic_p = picbuffer = malloc(bmhd.w * bmhd.h); if (formtype == PBMID) { /* unpack PBM */ for (y = 0; y < bmhd.h; y++, pic_p += bmhd.w) { if (bmhd.compression == cm_rle1) { body_p = LBMRLEDecompress((byte *)body_p, pic_p, bmhd.w); } else if (bmhd.compression == cm_none) { memcpy(pic_p, body_p, bmhd.w); body_p += Align(bmhd.w); } } } else { /* unpack ILBM */ planes = bmhd.nPlanes; if (bmhd.masking == ms_mask) planes++; rowsize = (bmhd.w + 15) / 16 * 2; switch (bmhd.nPlanes) { case 1: mungecall = MungeBitPlanes1; break; case 2: mungecall = MungeBitPlanes2; break; case 4: mungecall = MungeBitPlanes4; break; case 8: mungecall = MungeBitPlanes8; break; default: Error("Can't munge %i bit planes!\n", bmhd.nPlanes); } for (y = 0; y < bmhd.h; y++, pic_p += bmhd.w) { for (p = 0; p < planes; p++) if (bmhd.compression == cm_rle1) { body_p = LBMRLEDecompress((byte *)body_p, bitplanes[p], rowsize); } else if (bmhd.compression == cm_none) { memcpy(bitplanes[p], body_p, rowsize); body_p += rowsize; } mungecall(bmhd.w, pic_p); } } break; } LBM_P += Align(chunklength); } free(LBMbuffer); *picture = picbuffer; *palette = cmapbuffer; } /* * ============================================================================ * WRITE LBM * ============================================================================ */ /* * ============== * WriteLBMfile * ============== */ void WriteLBMfile(char *filename, byte *data, int width, int height, byte *palette) { byte *lbm, *lbmptr; int *formlength, *bmhdlength, *cmaplength, *bodylength; int length; bmhd_t basebmhd; lbm = lbmptr = malloc(width * height + 1000); /* start FORM */ *lbmptr++ = 'F'; *lbmptr++ = 'O'; *lbmptr++ = 'R'; *lbmptr++ = 'M'; formlength = (int *)lbmptr; lbmptr += 4; /* leave space for length */ *lbmptr++ = 'P'; *lbmptr++ = 'B'; *lbmptr++ = 'M'; *lbmptr++ = ' '; /* write BMHD */ *lbmptr++ = 'B'; *lbmptr++ = 'M'; *lbmptr++ = 'H'; *lbmptr++ = 'D'; bmhdlength = (int *)lbmptr; lbmptr += 4; /* leave space for length */ memset(&basebmhd, 0, sizeof(basebmhd)); basebmhd.w = BigShort((short)width); basebmhd.h = BigShort((short)height); basebmhd.nPlanes = BigShort(8); basebmhd.xAspect = BigShort(5); basebmhd.yAspect = BigShort(6); basebmhd.pageWidth = BigShort((short)width); basebmhd.pageHeight = BigShort((short)height); memcpy(lbmptr, &basebmhd, sizeof(basebmhd)); lbmptr += sizeof(basebmhd); length = lbmptr - (byte *)bmhdlength - 4; *bmhdlength = BigLong(length); if (length & 1) *lbmptr++ = 0; /* pad chunk to even offset */ /* write CMAP */ *lbmptr++ = 'C'; *lbmptr++ = 'M'; *lbmptr++ = 'A'; *lbmptr++ = 'P'; cmaplength = (int *)lbmptr; lbmptr += 4; /* leave space for length */ memcpy(lbmptr, palette, 768); lbmptr += 768; length = lbmptr - (byte *)cmaplength - 4; *cmaplength = BigLong(length); if (length & 1) *lbmptr++ = 0; /* pad chunk to even offset */ /* write BODY */ *lbmptr++ = 'B'; *lbmptr++ = 'O'; *lbmptr++ = 'D'; *lbmptr++ = 'Y'; bodylength = (int *)lbmptr; lbmptr += 4; /* leave space for length */ memcpy(lbmptr, data, width * height); lbmptr += width * height; length = lbmptr - (byte *)bodylength - 4; *bodylength = BigLong(length); if (length & 1) *lbmptr++ = 0; /* pad chunk to even offset */ /* done */ length = lbmptr - (byte *)formlength - 4; *formlength = BigLong(length); if (length & 1) *lbmptr++ = 0; /* pad chunk to even offset */ /* write output file */ SaveFile(filename, lbm, lbmptr - lbm); free(lbm); }