home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Creative Computers
/
CreativeComputers.iso
/
shareware
/
fractals
/
mandelsquare
/
mandelsquare-1.06.lha
/
PlayAnim.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-31
|
16KB
|
772 lines
/*
** MandelSquare - AmigaDOS 2.0/3.0 Mandelbrot set explorer
**
** PlayAnim.c, Routines to replay IFF-ANIM files
**
** Copyright ⌐ 1991-1992 by Olaf `Olsen' Barthel
** All Rights Reserved
*/
/* Animation module error codes, as returned by ValidateAnim(). */
enum { ANIMERR_WRONG_SEQUENCE=1,ANIMERR_NO_BODY,ANIMERR_WRONG_OPERATION,ANIMERR_NO_ANIM,
ANIMERR_MASKING,ANIMERR_IMAGE,ANIMERR_COMPRESSION,ANIMERR_NO_HEADER,ANIMERR_WRONG_SIZE,
ANIMERR_WRONG_MODE };
/* Animation file list entry. */
struct AnimNode
{
struct MinNode Node;
BitMapHeader *BitMapHeader;
AnimationHeader *AnimationHeader;
APTR Body;
ULONG *ViewModes,
Modes;
struct Palette *Palette;
};
/* Global flag. */
extern BYTE Is39;
/* In Double.c */
extern VOID FreeDBI(struct DBI *Info);
extern struct DBI * AllocDBI(struct Screen *Screen);
extern VOID SwapDBI(struct DBI *Info,BYTE Copy);
extern struct BitMap * GetDBI(struct DBI *Info);
extern VOID PaletteDBI(struct DBI *Info,struct Palette *Palette);
extern VOID StartDBI(struct DBI *Info,ULONG Jiffies);
extern VOID WaitDBI(struct DBI *Info);
/* 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);
/* In unvscomp.asm */
extern VOID __asm decode_vkplane(register __a0 UBYTE *deltabyte,register __a2 PLANEPTR plane,register __a3 UWORD *ytable,register __d2 UWORD bytesperrow);
/* Local, static routines. */
STATIC __inline VOID UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes);
STATIC __inline VOID SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable);
STATIC __inline VOID SetBODY(struct BitMap *BitMap,struct AnimNode *Node);
STATIC BYTE __regargs GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header);
STATIC BYTE __regargs GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header);
STATIC BYTE __regargs GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size);
STATIC VOID __regargs DeleteAnimNode(struct AnimNode *Node);
/* Exported routines. */
VOID DeleteAnim(struct MinList *List);
struct MinList * LoadAnim(STRPTR Name);
LONG ValidateAnim(struct MinList *List,struct Screen *Screen);
BYTE PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID));
/* UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes):
*
* CmpByteRun unpacker, based on original EA IFF code.
*/
STATIC __inline VOID
UnPackRow(BYTE **SourcePtr,BYTE **DestinationPtr,register WORD DestinationBytes)
{
register BYTE *Source = *SourcePtr,
*Destination = *DestinationPtr,
Char;
register WORD Count;
while(DestinationBytes > 0)
{
if((Count = *Source++) >= 0)
{
Count++;
if((DestinationBytes -= Count) < 0)
break;
else
{
do
*Destination++ = *Source++;
while(--Count);
}
}
else
{
if(Count != (WORD)(-128))
{
Count = -Count + 1;
if((DestinationBytes -= Count) < 0)
break;
else
{
Char = *Source++;
do
*Destination++ = Char;
while(--Count);
}
}
}
}
*SourcePtr = Source;
*DestinationPtr = Destination;
}
/* SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable):
*
* Unpack RIFF style delta data.
*/
STATIC __inline VOID
SetRIFF(struct BitMap *BitMap,struct AnimNode *Node,UWORD *LineTable)
{
register LONG *DeltaData = (LONG *)Node -> Body,
i;
/* Run down the planes... */
for(i = 0 ; i < BitMap -> Depth ; i++)
{
/* Any data to process? If so, unpack it. */
if(DeltaData[i])
decode_vkplane((UBYTE *)DeltaData + DeltaData[i],BitMap -> Planes[i],LineTable,BitMap -> BytesPerRow);
}
}
/* SetBODY(struct BitMap *BitMap,struct AnimNode *Node):
*
* Unpack CmpByteRun data.
*/
STATIC __inline VOID
SetBODY(struct BitMap *BitMap,struct AnimNode *Node)
{
PLANEPTR Planes[8],
*Destination;
BYTE *Source;
LONG i,j;
/* Copy the plane addresses, we will modify the pointers. */
for(i = 0 ; i < BitMap -> Depth ; i++)
Planes[i] = BitMap -> Planes[i];
/* Copy the data pointer, this will be modified as well. */
Source = (BYTE *)Node -> Body;
/* Run down the rows... */
for(i = 0 ; i < BitMap -> Rows ; i++)
{
/* Run down the planes... */
for(j = 0 ; j < BitMap -> Depth ; j++)
{
/* Remember the address. */
Destination = &Planes[j];
/* Unpack the data. */
UnPackRow(&Source,Destination,BitMap -> BytesPerRow);
}
}
}
/* GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header):
*
* Attach a bitmap header to an animnode.
*/
STATIC BYTE __regargs
GetBitMapHeader(struct AnimNode *Node,BitMapHeader *Header)
{
if(Node -> BitMapHeader = (BitMapHeader *)AllocVec(sizeof(BitMapHeader),MEMF_ANY))
{
CopyMem(Header,Node -> BitMapHeader,sizeof(BitMapHeader));
return(TRUE);
}
else
return(FALSE);
}
/* GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header):
*
* Attach and animation header to an animnode.
*/
STATIC BYTE __regargs
GetAnimationHeader(struct AnimNode *Node,AnimationHeader *Header)
{
if(Node -> AnimationHeader = (AnimationHeader *)AllocVec(sizeof(AnimationHeader),MEMF_ANY))
{
CopyMem(Header,Node -> AnimationHeader,sizeof(AnimationHeader));
return(TRUE);
}
else
return(FALSE);
}
/* GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size):
*
* Attach a colour map to an animnode.
*/
STATIC BYTE __regargs
GetColourMap(struct AnimNode *Node,UBYTE *Palette,LONG Size)
{
/* Determine number of palette entries. */
LONG Count = Size / 3;
/* Allocate a palette. */
if(Node -> Palette = AllocPalette(Count,Count == 256))
{
LONG R,G,B,
i;
/* Eight bits? */
if(Count == 256)
{
/* Run down the table, setting the eight bit triplets. */
for(i = 0 ; i < Count ; i++)
{
R = *Palette++;
G = *Palette++;
B = *Palette++;
SetPaletteTriplet(Node -> Palette,R,G,B,i);
}
}
else
{
/* Run down the table, setting the four bit triplets. */
for(i = 0 ; i < Count ; i++)
{
R = ((*Palette++) >> 4) & 0xF;
G = ((*Palette++) >> 4) & 0xF;
B = ((*Palette++) >> 4) & 0xF;
SetPaletteTriplet(Node -> Palette,R,G,B,i);
}
}
return(TRUE);
}
else
return(FALSE);
}
/* DeleteAnimNode(struct AnimNode *Node):
*
* Free an animation list node.
*/
STATIC VOID __regargs
DeleteAnimNode(struct AnimNode *Node)
{
if(Node -> BitMapHeader)
FreeVec(Node -> BitMapHeader);
if(Node -> AnimationHeader)
FreeVec(Node -> AnimationHeader);
if(Node -> Body)
FreeVec(Node -> Body);
if(Node -> Palette)
FreePalette(Node -> Palette);
FreeVec(Node);
}
/* DeleteAnim(struct MinList *List):
*
* Delete the contents of an entire animation list.
*/
VOID
DeleteAnim(struct MinList *List)
{
struct AnimNode *Node,
*Next;
/* Pick up the first node in the list. */
Node = (struct AnimNode *)List -> mlh_Head;
/* Run down the list... */
while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
{
/* Free the node. */
DeleteAnimNode(Node);
/* Skip to the next. */
Node = Next;
}
/* Remove the list itself. */
FreeVec(List);
}
/* LoadAnim(STRPTR Name):
*
* Load an ANIM5 animation file, creating a list suitable for
* submitting to PlayAnim() or ValidateAnim().
*/
struct MinList *
LoadAnim(STRPTR Name)
{
/* Data we will pick up on the fly. */
STATIC ULONG Properties[2 * 4] =
{
ID_ILBM,ID_BMHD,
ID_ILBM,ID_ANHD,
ID_ILBM,ID_CAMG,
ID_ILBM,ID_CMAP
};
/* Image and delta data. */
STATIC ULONG Stops[2 * 2] =
{
ID_ILBM,ID_BODY,
ID_ILBM,ID_DLTA
};
struct MinList *List;
/* Allocate the body list. */
if(List = (struct MinList *)AllocVec(sizeof(struct MinList),MEMF_ANY))
{
struct IFFHandle *Handle;
BYTE Success = TRUE;
/* Initialize the list header. */
NewList((struct List *)List);
/* Allocate an IFF handle. */
if(Handle = AllocIFF())
{
/* Open the file for reading. */
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
/* Make it known as a dos file. */
InitIFFasDOS(Handle);
/* Open the file for reading. */
if(!OpenIFF(Handle,IFFF_READ))
{
/* Remember the properties to store. */
if(!PropChunks(Handle,Properties,4))
{
/* Remember the chunks to stop at. */
if(!StopChunks(Handle,Stops,2))
{
struct StoredProperty *Prop;
struct ContextNode *Top;
/* Start scanning... */
while(Success && !ParseIFF(Handle,IFFPARSE_SCAN))
{
/* Pick up the topmost chunk. */
if(Top = CurrentChunk(Handle))
{
struct AnimNode *Node;
/* Allocate a new node. */
if(Node = AllocVec(sizeof(struct AnimNode),MEMF_ANY | MEMF_CLEAR))
{
/* Add it to the list. */
AddTail((struct List *)List,(struct Node *)Node);
/* Add the bitmap header. */
if(Prop = FindProp(Handle,ID_ILBM,ID_BMHD))
{
if(!GetBitMapHeader(Node,(BitMapHeader *)Prop -> sp_Data))
{
Success = FALSE;
break;
}
}
/* Add the animation header. */
if(Prop = FindProp(Handle,ID_ILBM,ID_ANHD))
{
if(!GetAnimationHeader(Node,(AnimationHeader *)Prop -> sp_Data))
{
Success = FALSE;
break;
}
}
/* Add the display mode information. */
if(Prop = FindProp(Handle,ID_ILBM,ID_CAMG))
{
Node -> ViewModes = &Node -> Modes;
Node -> Modes = *(ULONG *)Prop -> sp_Data;
}
/* Add the colour map information. */
if(Prop = FindProp(Handle,ID_ILBM,ID_CMAP))
{
if(!GetColourMap(Node,(UBYTE *)Prop -> sp_Data,Prop -> sp_Size))
{
Success = FALSE;
break;
}
}
/* Now we are about the read the BODY or the DLTA information,
* but not both.
*/
if(Node -> Body || (Top -> cn_ID == ID_BODY && !Node -> BitMapHeader) || (Top -> cn_ID == ID_DLTA && !Node -> AnimationHeader))
{
Success = FALSE;
break;
}
/* Allocate BODY or DLTA data, the animation header will
* provide the necessary information.
*/
if(Node -> Body = AllocVec(Top -> cn_Size,MEMF_ANY))
{
if(ReadChunkBytes(Handle,Node -> Body,Top -> cn_Size) != Top -> cn_Size)
Success = FALSE;
}
else
Success = FALSE;
}
else
Success = FALSE;
}
}
}
}
/* Close the handle. */
CloseIFF(Handle);
}
/* Close the file. */
Close(Handle -> iff_Stream);
}
/* Free the handle data. */
FreeIFF(Handle);
}
/* Delete the animation list if anything went wrong. */
if(!Success)
{
DeleteAnim(List);
List = NULL;
}
}
return(List);
}
/* ValidateAnim(struct MinList *List,struct Screen *Screen):
*
* Validate the loaded animation and see if it fits both
* the screen and the machine.
*/
LONG
ValidateAnim(struct MinList *List,struct Screen *Screen)
{
struct AnimNode *Node,
*Next;
BitMapHeader *Header;
LONG Frames = 0;
/* Is there any data? */
Node = (struct AnimNode *)List -> mlh_Head;
if(Node -> Node . mln_Succ)
{
/* We _need_ a bitmap header. */
if(!Node -> BitMapHeader)
return(ANIMERR_WRONG_SEQUENCE);
else
Header = Node -> BitMapHeader;
}
else
return(ANIMERR_NO_ANIM);
/* Now scan the list... */
while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
{
/* Is the display mode available? */
if(Node -> ViewModes)
{
if(ModeNotAvailable(*Node -> ViewModes))
return(ANIMERR_WRONG_MODE);
}
/* Is the image too `deep'? */
if(Node -> BitMapHeader)
{
if(Node -> BitMapHeader -> nPlanes > 5 && !Is39)
return(ANIMERR_WRONG_MODE);
}
/* No delta or image data available? */
if(!Node -> Body)
return(ANIMERR_NO_BODY);
/* Animation header available? */
if(Node -> AnimationHeader)
{
/* Only type 5 animations are supported
* so far...
*/
if(Node -> AnimationHeader -> operation != 5)
return(ANIMERR_WRONG_OPERATION);
/* No masking, please. */
if(Node -> AnimationHeader -> mask)
return(ANIMERR_MASKING);
Frames++;
}
/* Bitmap header available? */
if(Node -> BitMapHeader)
{
/* Strange image information? */
if(Node -> BitMapHeader -> nPlanes < 1 || Node -> BitMapHeader -> nPlanes > 8 || !Node -> BitMapHeader -> w || !Node -> BitMapHeader -> h)
return(ANIMERR_IMAGE);
/* No masking, please. */
if(Node -> BitMapHeader -> masking)
return(ANIMERR_MASKING);
/* The image _has_ to be compressed! */
if(Node -> BitMapHeader -> compression != 1)
return(ANIMERR_COMPRESSION);
/* Does it fit the screen? */
if(Node -> BitMapHeader -> w != Screen -> Width || Node -> BitMapHeader -> h != Screen -> Height || Node -> BitMapHeader -> nPlanes != Screen -> RastPort . BitMap -> Depth)
return(ANIMERR_WRONG_SIZE);
Frames++;
}
Node = Next;
}
/* There should be at least two frames. */
if(Frames < 2)
return(ANIMERR_NO_ANIM);
else
{
if(!Header)
return(ANIMERR_NO_HEADER);
else
return(0);
}
}
/* PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID)):
*
* Replay an animation.
*/
BYTE
PlayAnim(struct MinList *List,struct Screen *Screen,BYTE (*CheckAbort)(VOID))
{
struct DBI *Info;
BYTE Result = FALSE;
/* Allocate double-buffering information. */
if(Info = AllocDBI(Screen))
{
UWORD *LineTable;
/* Set up the line byte modulo table. */
if(LineTable = (UWORD *)AllocVec(sizeof(UWORD) * Screen -> Height,MEMF_ANY))
{
struct AnimNode *Node,
*Next;
struct BitMap *BitMap;
BYTE Done = FALSE;
UWORD Count,
i;
/* Get the bitmap to render into. */
BitMap = GetDBI(Info);
/* Set up the table information. */
for(i = Count = 0 ; i < BitMap -> Rows ; i++)
{
LineTable[i] = Count;
Count += BitMap -> BytesPerRow;
}
/* Run the loop... */
do
{
/* Get the first list entry, this
* should be the first image.
*/
Node = (struct AnimNode *)List -> mlh_Head;
/* Run down the list... */
while(Next = (struct AnimNode *)Node -> Node . mln_Succ)
{
/* Get the bitmap to render into. */
BitMap = GetDBI(Info);
/* Any palette to set? */
if(Node -> Palette)
PaletteDBI(Info,Node -> Palette);
/* Delta data to unpack? */
if(Node -> AnimationHeader)
{
/* Any inter-frame delay? */
if(Node -> AnimationHeader -> reltime)
{
/* Start the timer... */
StartDBI(Info,Node -> AnimationHeader -> reltime);
/* Unpack the delta data. */
SetRIFF(BitMap,Node,LineTable);
/* Wait for timer to elapse. */
WaitDBI(Info);
}
else
SetRIFF(BitMap,Node,LineTable);
}
else
SetBODY(BitMap,Node);
/* Swap in the bitmap just rendered. */
SwapDBI(Info,TRUE);
/* Check for abort action. */
if((*CheckAbort)())
{
Done = TRUE;
break;
}
/* Skip to the next frame. */
Node = Next;
}
/* Check for abort action. */
if((*CheckAbort)())
Done = TRUE;
}
while(!Done);
/* Free the line modulo table. */
FreeVec(LineTable);
/* We are successful so far. */
Result = TRUE;
}
/* Free the double-buffering information. */
FreeDBI(Info);
}
return(Result);
}