home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d8xx
/
d835
/
mandelsquare.lha
/
MandelSquare
/
MandelSquare-1.06.lha
/
ILBM.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-20
|
18KB
|
836 lines
/*
** MandelSquare - AmigaDOS 2.0/3.0 Mandelbrot set explorer
**
** ILBM.c, Routines to load and save IFF-ILBM files
**
** Copyright © 1991-1992 by Olaf `Olsen' Barthel
** All Rights Reserved
*/
/* A picture handle. */
struct PictureInfo
{
BitMapHeader BitMapHeader;
MandelHeader MandelHeader;
struct Palette * Palette;
ULONG ViewModes;
struct BitMap * BitMap;
};
/* Global flag. */
extern BYTE Is39;
/* In Packer.c */
extern LONG __regargs PackRow(BYTE **pSource,BYTE *dest,LONG rowSize);
extern VOID __regargs UnPackRow(BYTE **pSource,BYTE **pDest,WORD dstBytes);
/* In Palette.c */
extern VOID FreePalette(struct Palette *Palette);
extern struct Palette * AllocPalette(LONG NumColours,BYTE TrueColour);
extern struct Palette * GetPalette(struct Screen *Screen,struct Palette *Palette);
extern VOID LoadPalette(struct Screen *Screen,struct Palette *Palette,LONG NumColours);
extern LONG GetPaletteSize(struct Palette *Palette);
extern BYTE GetPaletteTriplet(struct Palette *Palette,UBYTE *Triplet,LONG Index);
extern BYTE SetPaletteTriplet(struct Palette *Palette,UBYTE R,UBYTE G,UBYTE B,LONG Index);
extern ULONG GetPaletteEntry(struct Palette *Palette,LONG Index);
extern BYTE SetPaletteEntry(struct Palette *Palette,ULONG Entry,LONG Index);
/* Local, static routines. */
STATIC VOID __regargs GetBody(struct BitMap *BitMap,APTR Body);
STATIC BYTE __regargs GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size);
STATIC BYTE __regargs PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel);
STATIC BYTE __regargs PutCRange(struct IFFHandle *Handle,CRange *Range);
/* Exported routines. */
VOID FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard);
struct BitMap * AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard);
BYTE PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap);
BYTE PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort);
BYTE PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort);
BYTE PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen);
VOID FreePicture(struct PictureInfo *Info);
struct PictureInfo * LoadPicture(STRPTR Name);
BYTE SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel);
/* GetBody(struct BitMap *BitMap,APTR Body):
*
* Unpack compressed data.
*/
STATIC VOID __regargs
GetBody(struct BitMap *BitMap,APTR Body)
{
PLANEPTR Planes[8];
BYTE *Source;
LONG i,j;
/* Get the source data pointer, we will modify it. */
Source = (BYTE *)Body;
/* Copy the bitplane pointers. */
for(i = 0 ; i < BitMap -> Depth ; i++)
Planes[i] = BitMap -> Planes[i];
/* CmpByteRun decompression. */
for(i = 0 ; i < BitMap -> Rows ; i++)
{
for(j = 0 ; j < BitMap -> Depth ; j++)
UnPackRow(&Source,&Planes[j],BitMap -> BytesPerRow);
}
}
/* GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size):
*
* Fill in colour map information.
*/
STATIC BYTE __regargs
GetColourMap(struct PictureInfo *Info,UBYTE *Palette,LONG Size)
{
/* Get the number of colours. */
LONG NumColours = Size / 3;
/* Allocate palette information. */
if(Info -> Palette = AllocPalette(NumColours,NumColours == 256))
{
UWORD R,G,B;
LONG i;
/* Set the 8 bit triplets. */
if(NumColours == 256)
{
for(i = 0 ; i < NumColours ; i++)
{
R = *Palette++;
G = *Palette++;
B = *Palette++;
SetPaletteTriplet(Info -> Palette,R,G,B,i);
}
}
else
{
/* Set the 4 bit triplets. */
for(i = 0 ; i < NumColours ; i++)
{
R = ((*Palette++) >> 4) & 0xF;
G = ((*Palette++) >> 4) & 0xF;
B = ((*Palette++) >> 4) & 0xF;
SetPaletteTriplet(Info -> Palette,R,G,B,i);
}
}
return(TRUE);
}
else
return(FALSE);
}
/* PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel):
*
* Save the mandelbrot information chunk.
*/
STATIC BYTE __regargs
PutMandel(struct IFFHandle *Handle,MandelHeader *Mandel)
{
if(!PushChunk(Handle,0,ID_MAND,sizeof(MandelHeader)))
{
if(WriteChunkRecords(Handle,Mandel,sizeof(MandelHeader),1) == 1)
{
if(!PopChunk(Handle))
return(TRUE);
}
}
return(FALSE);
}
/* PutCRange(struct IFFHandle *Handle,CRange *Range):
*
* Save the colour cycling chunk.
*/
STATIC BYTE __regargs
PutCRange(struct IFFHandle *Handle,CRange *Range)
{
if(!PushChunk(Handle,0,ID_CRNG,sizeof(CRange)))
{
if(WriteChunkRecords(Handle,Range,sizeof(CRange),1) == 1)
{
if(!PopChunk(Handle))
return(TRUE);
}
}
return(FALSE);
}
/* FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard):
*
* Free bitmap memory.
*/
VOID
FreeCustomBitMap(struct BitMap *BitMap,BYTE Standard)
{
if(Is39)
FreeBitMap(BitMap);
else
{
if(BitMap)
{
WORD i;
for(i = 0 ; i < BitMap -> Depth ; i++)
{
if(BitMap -> Planes[i])
FreeVec(BitMap -> Planes[i]);
}
FreeVec(BitMap);
}
}
}
/* AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard):
*
* Allocate bitmap memory.
*/
struct BitMap *
AllocCustomBitMap(UWORD Depth,UWORD Width,UWORD Height,BYTE Standard)
{
if(Is39)
{
extern struct Screen *Screen;
/* Note: `Standard' assumes that a BitMap with properly
* set line modulo values (i.e. no chunky, interleaved
* or whatever layout possible) will be allocated and
* returned. This BitMap will never be used for
* screen display but rather as a temporary buffer
* for image compression.
*/
if(Standard)
return(AllocBitMap(Width,Height,Depth,BMF_CLEAR,NULL));
else
return(AllocBitMap(Width,Height,Depth,BMF_CLEAR | BMF_DISPLAYABLE,Screen -> RastPort . BitMap));
}
else
{
struct BitMap *BitMap;
/* Allocate the bitmap body. */
if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY | MEMF_CLEAR))
{
BYTE Success = TRUE;
LONG PlaneSize,
i;
/* Initialize the bitmap. */
InitBitMap(BitMap,Depth,Width,Height);
/* Get the plane size. */
PlaneSize = BitMap -> BytesPerRow * BitMap -> Rows;
/* Allocate the single bitplanes. */
for(i = 0 ; Success && i < Depth ; i++)
{
if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PlaneSize,MEMF_CHIP | MEMF_CLEAR)))
Success = FALSE;
}
/* Return the result. */
if(Success)
return(BitMap);
else
FreeCustomBitMap(BitMap,Standard);
}
}
return(NULL);
}
/* PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap):
*
* Save a bitmap to disk.
*/
BYTE
PutBitMap(struct IFFHandle *Handle,struct BitMap *BitMap)
{
PLANEPTR *Planes;
BYTE *PackBuffer,
Success = FALSE;
LONG PackedBytes,
i,j;
/* Allocate the bitplane information. */
if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
{
/* Allocate the compression buffer. */
if(PackBuffer = (BYTE *)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
{
/* Copy the planes over. */
for(i = 0 ; i < BitMap -> Depth ; i++)
Planes[i] = BitMap -> Planes[i];
if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
{
Success = TRUE;
/* Run down the rows. */
for(i = 0 ; Success && i < BitMap -> Rows ; i++)
{
for(j = 0 ; Success && j < BitMap -> Depth ; j++)
{
/* Pack the data. */
PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
/* Write it to disk. */
if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
Success = FALSE;
}
}
if(PopChunk(Handle))
Success = FALSE;
}
FreeVec(PackBuffer);
}
FreeVec(Planes);
}
return(Success);
}
/* PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort):
*
* Save the display modes to disk.
*/
BYTE
PutViewModes(struct IFFHandle *Handle,struct ViewPort *VPort)
{
ULONG ViewModes = GetVPModeID(VPort);
if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
{
if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
{
if(!PopChunk(Handle))
return(TRUE);
}
}
return(FALSE);
}
/* PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort):
*
* Save the colour map to disk.
*/
BYTE
PutColourMap(struct IFFHandle *Handle,struct ViewPort *VPort)
{
ColorRegister Colour;
LONG i;
if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
{
/* Eight or four bit triplets? */
if(VPort -> ColorMap -> Count == 256)
{
ULONG Triplet[3];
/* Run down the colour map... */
for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
{
/* Get the colour information, returned
* as three 32 bit quantities.
*/
GetRGB32(VPort -> ColorMap,i,1,Triplet);
/* As of this writing, only eight
* bit quantities are supported for
* CMAP chunks.
*/
Colour . red = Triplet[0] >> 24;
Colour . green = Triplet[1] >> 24;
Colour . blue = Triplet[2] >> 24;
/* Write the data. */
if(WriteChunkRecords(Handle,&Colour,3,1) != 1)
return(FALSE);
}
}
else
{
ULONG Value,
R,G,B;
/* Run down the colour map... */
for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
{
/* Get the colour map entry. */
Value = GetRGB4(VPort -> ColorMap,i);
/* Split the colour information. */
R = (Value >> 8) & 0xF;
G = (Value >> 4) & 0xF;
B = (Value ) & 0xF;
/* Fill it in. */
Colour . red = (R << 4) | R;
Colour . green = (G << 4) | G;
Colour . blue = (B << 4) | B;
/* Write the data. */
if(WriteChunkRecords(Handle,&Colour,3,1) != 1)
return(FALSE);
}
}
if(!PopChunk(Handle))
return(TRUE);
}
return(FALSE);
}
/* PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen):
*
* Save the bitmap header to disk.
*/
BYTE
PutBitMapHeader(struct IFFHandle *Handle,struct Screen *Screen)
{
BitMapHeader Header;
struct DisplayInfo DisplayInfo;
/* Fill in the standard data. */
Header . w = Screen -> Width;
Header . h = Screen -> Height;
Header . pageWidth = Screen -> Width;
Header . pageHeight = Screen -> Height;
Header . x = 0;
Header . y = 0;
Header . nPlanes = Screen -> RastPort . BitMap -> Depth;
Header . masking = 0;
Header . compression = 1;
Header . pad1 = 0;
Header . transparentColor = 0;
/* Get the aspect ration information. */
if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Screen -> ViewPort)))
{
/* Fill it in. */
Header . xAspect = DisplayInfo . Resolution . x;
Header . yAspect = DisplayInfo . Resolution . y;
/* Write the data. */
if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
{
if(WriteChunkRecords(Handle,&Header,sizeof(BitMapHeader),1) == 1)
{
if(!PopChunk(Handle))
return(TRUE);
}
}
}
return(FALSE);
}
/* FreePicture(struct PictureInfo *Info):
*
* Free picture information.
*/
VOID
FreePicture(struct PictureInfo *Info)
{
if(Info)
{
/* Free the bitmap. */
if(Info -> BitMap)
FreeCustomBitMap(Info -> BitMap,TRUE);
/* Free the palette. */
if(Info -> Palette)
FreePalette(Info -> Palette);
/* Free the information buffer. */
FreeVec(Info);
}
}
/* LoadPicture(STRPTR Name):
*
* Load an IFF-ILBM image file.
*/
struct PictureInfo *
LoadPicture(STRPTR Name)
{
/* The information we wil pick up on the fly. */
STATIC ULONG Properties[2 * 4] =
{
ID_ILBM,ID_BMHD,
ID_ILBM,ID_CAMG,
ID_ILBM,ID_CMAP,
ID_ILBM,ID_MAND
};
struct PictureInfo *Info;
/* Allocate the information buffer. */
if(Info = (struct PictureInfo *)AllocVec(sizeof(struct PictureInfo),MEMF_ANY | MEMF_CLEAR))
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
/* Allocate iff handle. */
if(Handle = AllocIFF())
{
/* Open file for reading. */
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
/* Make it known as a DOS file. */
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_READ))
{
/* Remember the properties to store. */
if(!PropChunks(Handle,Properties,4))
{
/* Stop at the BODY chunk. */
if(!StopChunk(Handle,ID_ILBM,ID_BODY))
{
struct StoredProperty *Prop;
/* Scan for it... */
if(!ParseIFF(Handle,IFFPARSE_SCAN))
{
Success = TRUE;
/* Try to find the bitmap header. */
if(Prop = FindProp(Handle,ID_ILBM,ID_BMHD))
{
CopyMem(Prop -> sp_Data,&Info -> BitMapHeader,sizeof(BitMapHeader));
/* No weird data, please. */
if(Info -> BitMapHeader . nPlanes < 1 || Info -> BitMapHeader . nPlanes > 8 || Info -> BitMapHeader . w != Info -> BitMapHeader . pageWidth || Info -> BitMapHeader . h != Info -> BitMapHeader . pageHeight)
Success = FALSE;
/* No masking and CmpByteRun compression, please. */
if(Info -> BitMapHeader . masking || Info -> BitMapHeader . compression != 1)
Success = FALSE;
}
else
Success = FALSE;
/* Can we continue? */
if(Success)
{
/* Check for CAMG chunk... */
if(Prop = FindProp(Handle,ID_ILBM,ID_CAMG))
{
Info -> ViewModes = *(ULONG *)Prop -> sp_Data;
/* Mask out the old 1.3 bits... */
if(!(Info -> ViewModes & MONITOR_ID_MASK) || ((Info -> ViewModes & EXTENDED_MODE) && !(Info -> ViewModes & 0xFFFF0000)))
Info -> ViewModes &= ~(EXTENDED_MODE | SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);
/* Can we get along with it? */
if(!(Info -> ViewModes & EXTENDED_MODE) && (Info -> ViewModes & 0xFFFF0000))
Prop = NULL;
else
{
/* Is the display mode available? */
if(ModeNotAvailable(Info -> ViewModes))
{
/* Mask out the valid bits. */
Info -> ViewModes &= (LACE | HIRES | HAM | EXTRA_HALFBRITE);
/* Any chance? */
if(ModeNotAvailable(Info -> ViewModes))
Success = FALSE;
}
}
}
/* No chance so far, try to make up the
* data from scratch.
*/
if(!Prop && Success)
{
extern struct GfxBase *GfxBase;
Info -> ViewModes = NULL;
if(Info -> BitMapHeader . pageHeight > ((GfxBase -> DisplayFlags & PAL) ? 256 : 200))
Info -> ViewModes |= LACE;
if(Info -> BitMapHeader . pageWidth >= 640)
Info -> ViewModes |= HIRES;
if(Info -> BitMapHeader . nPlanes == 6)
Info -> ViewModes |= HAM;
}
/* Try to pick up the colour map. */
if(Success)
{
if(Prop = FindProp(Handle,ID_ILBM,ID_CMAP))
{
if(!GetColourMap(Info,(UBYTE *)Prop -> sp_Data,Prop -> sp_Size))
Success = FALSE;
}
}
/* We _need_ the mandelbrot data. */
if(Success)
{
if(Prop = FindProp(Handle,ID_ILBM,ID_MAND))
CopyMem(Prop -> sp_Data,&Info -> MandelHeader,sizeof(MandelHeader));
else
Success = FALSE;
}
/* Successful so far? */
if(Success)
{
struct ContextNode *BodyChunk;
Success = FALSE;
if(BodyChunk = CurrentChunk(Handle))
{
APTR Body;
/* Allocate space for the body data. */
if(Body = AllocVec(BodyChunk -> cn_Size,MEMF_ANY))
{
/* Read the data. */
if(ReadChunkRecords(Handle,Body,BodyChunk -> cn_Size,1) == 1)
{
/* Allocate a suitable bitmap. */
if(Info -> BitMap = AllocCustomBitMap(Info -> BitMapHeader . nPlanes,Info -> BitMapHeader . w,Info -> BitMapHeader . h,TRUE))
{
/* Unpack the data. */
GetBody(Info -> BitMap,Body);
Success = TRUE;
}
}
FreeVec(Body);
}
}
}
}
}
}
}
CloseIFF(Handle);
}
Close(Handle -> iff_Stream);
}
FreeIFF(Handle);
}
if(!Success)
{
FreePicture(Info);
Info = NULL;
}
}
return(Info);
}
/* SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel):
*
* Save the screen to an IFF-ILBM disk file.
*/
BYTE
SavePicture(STRPTR Name,struct Screen *Screen,MandelHeader *Mandel)
{
struct BitMap *BitMap;
BYTE Success = FALSE,
Delete = FALSE;
/* Allocate local bitmap, don't use the plain screen bitmap. */
if(BitMap = AllocCustomBitMap(Screen -> RastPort . BitMap -> Depth,Screen -> Width,Screen -> Height,TRUE))
{
struct IFFHandle *Handle;
/* Copy the screen bitmap. */
BltBitMap(Screen -> RastPort . BitMap,0,0,BitMap,0,0,Screen -> Width,Screen -> Height,0xC0,0xFF,NULL);
/* Do the vanilla setup. */
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
{
Delete = TRUE;
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_WRITE))
{
if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
{
/* Put the bitmap header. */
if(PutBitMapHeader(Handle,Screen))
{
/* Put the colour information. */
if(PutColourMap(Handle,&Screen -> ViewPort))
{
/* Put the display modes. */
if(PutViewModes(Handle,&Screen -> ViewPort))
{
CRange Range;
/* Initialize the colour cycling chunk. */
Range . pad1 = 0;
Range . rate = 16384 / (60 / 20);
Range . flags = RNG_ACTIVE;
Range . low = 2;
Range . high = Screen -> ViewPort . ColorMap -> Count - 1;
/* Put the colour cycling chunk. */
if(PutCRange(Handle,&Range))
{
/* Put the mandelbrot information chunk. */
if(PutMandel(Handle,Mandel))
{
/* Put the bitmap data. */
if(PutBitMap(Handle,BitMap))
{
/* We're done now. */
if(!PopChunk(Handle))
Success = TRUE;
}
}
}
}
}
}
}
CloseIFF(Handle);
}
if(!Close(Handle -> iff_Stream))
Success = FALSE;
}
FreeIFF(Handle);
}
FreeCustomBitMap(BitMap,TRUE);
}
if(Success)
SetProtection(Name,FIBF_EXECUTE);
else
{
if(Delete)
DeleteFile(Name);
}
return(Success);
}