449 lines
11 KiB
C++
449 lines
11 KiB
C++
/* common/lbmlib.c */
|
|
|
|
#include <common/cmdlib.h>
|
|
#include <common/lbmlib.h>
|
|
|
|
/*
|
|
* ============================================================================
|
|
* 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!
|
|
* ================
|
|
*/
|
|
uint8_t *
|
|
LBMRLEDecompress(uint8_t *source, uint8_t *unpacked, int bpwidth)
|
|
{
|
|
int count;
|
|
uint8_t 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
|
|
uint8_t bitplanes[9][BPLANESIZE]; /* max size 1024 by 9 bit planes */
|
|
|
|
/*
|
|
* =================
|
|
* MungeBitPlanes8
|
|
* This destroys the bit plane data!
|
|
* =================
|
|
*/
|
|
void
|
|
MungeBitPlanes8(int width, uint8_t *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, uint8_t *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, uint8_t *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, uint8_t *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, uint8_t **picture, uint8_t **palette)
|
|
{
|
|
uint8_t *LBMbuffer, *picbuffer, *cmapbuffer;
|
|
int y, p, planes;
|
|
uint8_t *LBM_P, *LBMEND_P;
|
|
uint8_t *pic_p;
|
|
uint8_t *body_p;
|
|
unsigned rowsize;
|
|
|
|
int formtype, formlength;
|
|
int chunktype, chunklength;
|
|
void (*mungecall) (int, uint8_t *);
|
|
|
|
/* 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((uint8_t *)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((uint8_t *)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, uint8_t *data, int width, int height, uint8_t *palette)
|
|
{
|
|
uint8_t *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 - (uint8_t *)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 - (uint8_t *)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 - (uint8_t *)bodylength - 4;
|
|
*bodylength = BigLong(length);
|
|
if (length & 1)
|
|
*lbmptr++ = 0; /* pad chunk to even offset */
|
|
|
|
/* done */
|
|
length = lbmptr - (uint8_t *)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);
|
|
}
|