brender-v1.1.2/FMT/LOADIFF.C
2022-05-04 18:14:23 -07:00

271 lines
6.6 KiB
C

/*
* Copyright (c) 1993-1995 by Argonaut Technologies Limited. All rights reserved.
*
* $Id: loadiff.c 1.4 1995/08/31 16:28:17 sam Exp $
* $Locker: $
*
* Loader for Amiga .IFF/.LBM format
* support for 8 bit index palette based
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "brender.h"
#include "fmt.h"
#include "fw.h"
static char rscid[] = "$Id: loadiff.c 1.4 1995/08/31 16:28:17 sam Exp $";
static int readline(char *mblock,int bytes,void *fh);
static void planes2bytes(br_pixelmap *pm,char *block,int line);
#define RED 2
#define GRN 1
#define BLU 0
#define PAD 3
#define PACKET_SIZE 4 /* block size */
#define MAX_PALETTE 768 /* 256 colours */
#define RUN_LENGTH 0x80 /* rle bit field */
#define BITMAP_HEADER "BMHD"
#define COLOUR_MAP "CMAP"
#define IMAGE_DATA "BODY"
#define swapl(n) (((n & 0xff000000) >> 24) + \
((n & 0x00ff0000) >> 8) + \
((n & 0x0000ff00) << 8) + \
((n & 0x000000ff) <<24))
#define swapi(n) (((n & 0xff00) >> 8) | \
((n & 0x00ff) << 8))
#define pixels2bytes(n) ((n+7)/8)
#pragma pack (1)
static struct {
char type[4]; /* iff/lbm sig, 'FORM','LIST' or 'CAT ' */
unsigned int size; /* swapl(n) approx. size of file */
char subtype[4]; /* 'ILBM' - image planes or 'PBM ' - byte oriented */
} IFFheader;
static struct {
unsigned short w; /* width of image in pixels */
unsigned short h; /* height of image in pixels */
short x; /* x coord of uppr left of image relative to screen */
short y; /* y coord or uppr left of image relative to screen */
char nPlanes; /* number of colour planes required to display image (n/a)*/
char masking; /* image data interleaved with mask */
/* 0 - no mask, 1 - mask */
/* 2 - mask with transparent colour, 3 - lasso mask */
char compression; /* 0 - uncompressed image data, 1 - compressed (rle) */
char padl; /* pad byte n/a */
unsigned short transparentColour; /* colour index in image considered transparent */
char xAspect; /* aspect ratio */
char yAspect; /* aspect ratio */
short pageW; /* size of source screen */
short pageH; /* size of source screen */
} BMHD;
static struct {
char red;
char green;
char blue;
} RGB;
static char masktable[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 };
static char bittable[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
#pragma pack ()
br_pixelmap * BR_PUBLIC_ENTRY BrFmtIFFLoad(char *name,br_uint_32 flags)
{
void *fh;
int open_mode = BR_FS_MODE_BINARY;
br_pixelmap *pm,*palette;
char block[4],*mblock;
unsigned int block_length;
br_uint_8 type;
br_uint_16 i,palette_size;
br_uint_32 bytes_per_line;
fh = BrFileOpenRead(name,0,NULL,&open_mode);
if(fh == NULL)
BR_ERROR1("Could not open '%s' for reading",name);
if(BrFileRead(&IFFheader,1,sizeof(IFFheader),fh) != sizeof(IFFheader))
BR_ERROR1("Unable to read header information from '%s'",name);
if(!memcmp(IFFheader.type,"FORM",4) ||
!memcmp(IFFheader.type,"LIST",4) ||
!memcmp(IFFheader.type,"CAT ",4))
{
do
{
if(BrFileRead(block,1,PACKET_SIZE,fh) != PACKET_SIZE)
BR_ERROR1("Unable to read block descriptor from '%s'",name);
if(BrFileRead(&block_length,1,PACKET_SIZE,fh) != PACKET_SIZE)
BR_ERROR1("Unable to read block length from '%s'",name);
block_length = swapl(block_length);
if(block_length & 1)
++block_length; /* make block size even */
if(!memcmp(block,BITMAP_HEADER,4))
{
/*
* Image block information header
*/
if(BrFileRead(&BMHD,1,sizeof(BMHD),fh) != sizeof(BMHD))
BR_ERROR1("Unable to read bitmap header in '%s'",name);
BMHD.w = swapi(BMHD.w);
BMHD.h = swapi(BMHD.h);
if(!memcmp(IFFheader.subtype,"ILBM",4))
bytes_per_line = pixels2bytes(BMHD.w) * BMHD.nPlanes;
else
bytes_per_line = BMHD.w;
}
else if(!memcmp(block,COLOUR_MAP,4))
{
/*
* Palette
*/
if(block_length <= MAX_PALETTE)
{
palette_size = block_length/3;
palette = BrPixelmapAllocate(BR_PMT_RGBX_888,1,256,NULL,0);
palette->identifier = BrResStrDup(palette, name);
for(i=0; i<palette_size; i++)
{
if(BrFileRead(&RGB,1,sizeof(RGB),fh) != sizeof(RGB))
BR_ERROR1("Unable to read palette from '%s'",name);
((char *)(palette->pixels))[i*4+RED] = RGB.red;
((char *)(palette->pixels))[i*4+GRN] = RGB.green;
((char *)(palette->pixels))[i*4+BLU] = RGB.blue;
((char *)(palette->pixels))[i*4+PAD] = 0;
}
}
}
else if(!memcmp(block,IMAGE_DATA,4))
{
/*
* Raw image data
*/
pm = BrPixelmapAllocate(BR_PMT_INDEX_8,BMHD.w,BMHD.h,NULL,0);
pm->identifier = BrResStrDup(pm, name);
mblock = BrMemAllocate(bytes_per_line,BR_MEMORY_SCRATCH);
for(i=0;i<BMHD.h;i++)
{
if(BMHD.compression)
{
if(readline(mblock,bytes_per_line,fh) != bytes_per_line)
BR_ERROR1("Unable to read image data from '%s'",name);
}
else
{
if(BrFileRead(mblock,1,bytes_per_line,fh) != bytes_per_line)
BR_ERROR1("Unable to read image data from '%s'",name);
}
if(!memcmp(IFFheader.subtype,"ILBM",4) ||
(!memcmp(IFFheader.subtype,"PBM ",4) &&
BMHD.nPlanes < 8))
/* bitmap split into image planes */
planes2bytes(pm,mblock,i);
else
/* planar data */
memcpy((char *)pm->pixels+i*pm->row_bytes,mblock,BMHD.w);
}
BrMemFree(mblock);
}
else BrFileAdvance(block_length,fh); /* skip unknown block */
}
while(!BrFileEof(fh) && memcmp(block,IMAGE_DATA,4));
pm->map = palette; /* palette may be after image block in file */
BrFileClose(fh);
return pm;
}
else
BR_ERROR1("'%s' is not a valid IFF file",name);
return NULL;
}
static int readline(char *mblock,int bytes,void *fh)
{
short c,i, n = 0;
do
{
c = BrFileGetChar(fh) & 0xff;
if(c & RUN_LENGTH) /* run length */
{
if(c != 0x80)
{
i = ((~c) & 0xff)+2;
c = BrFileGetChar(fh);
while(i--)
mblock[n++] = c;
}
}
else /* string */
{
i = (c & 0xff)+1;
while(i--)
mblock[n++] = BrFileGetChar(fh);
}
}
while(n < bytes);
return n;
}
static void planes2bytes(br_pixelmap *pm,char *block,int line)
{
int i,j,n;
char *src;
n = pixels2bytes(BMHD.w);
for(i=0;i<BMHD.w;++i) /* scan through pixels */
{
((char *)(pm->pixels))[line*pm->row_bytes+i] = 0;
src = block;
for(j=0; j<BMHD.nPlanes; ++j) /* fetch each planar pixel */
{
if(src[(i >> 3)] & masktable[i & 0x0007])
((char *)(pm->pixels))[line*pm->row_bytes+i] |= bittable[j];
src += n;
}
}
}