/** PreLoadAnim.c *********************************************************** * * Load an ILBM raster image file into memory structures * This is a modified version of ReadPict.c dated 23-Jan-86. * * Modified by Gary Bonham, SPARTA, Inc. 15 Aug 1986 * Modified by Olaf `Olsen' Barthel, 16-Sep-1991 * ***************************************************************************/ #include #include #include #include "ilbm.h" #include "readpict.h" #include "preloadanim.h" /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */ #define EXDepth 5 #define maxColorReg (1 << EXDepth) #define GetANHD(context,anHdr) IFFReadBytes(context,(BYTE *)anHdr,sizeof(AnimationHeader)) STATIC IFFP GetCMAP(GroupContext *ilbmContext,WORD *colorMap,UBYTE *pNColorRegs); STATIC IFFP GetPrILBM(GroupContext *parent); STATIC IFFP GetLiILBM(GroupContext *parent); STATIC IFFP GetFoANIM(GroupContext *parent); STATIC IFFP __regargs PreLoadAnimation(BPTR file,ILBMFrame *iFrame); VOID ClosePreLoadIFF(VOID); BYTE OpenPreLoadIFF(BPTR file); extern struct Screen *Screen; struct IFFfile *IFFfileList; /*------------ ILBM reader -----------------------------------------------*/ /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file. * We allocate one of these on the stack for every LIST or FORM encountered * in the file and use it to hold BMHD & CMAP properties. We also allocate * an initial one for the whole file. * We allocate a new GroupContext (and initialize it by OpenRIFF or * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's * just a context for reading (nested) chunks. * * If we were to scan the entire example file outlined below: * reading proc(s) new new * * --whole file-- ReadPicture+ReadIFF GroupContext ILBMFrame * CAT ReadICat GroupContext * LIST GetLiILBM+ReadIList GroupContext ILBMFrame * PROP ILBM GetPrILBM GroupContext * CMAP GetCMAP * BMHD GetBMHD * FORM ILBM GetFoILBM GroupContext ILBMFrame * BODY GetBODY * FORM ILBM GetFoILBM GroupContext ILBMFrame * BODY GetBODY * FORM ILBM GetFoILBM GroupContext ILBMFrame */ /* ---------- GetCMAP ------------------------------------------------*/ /* pNColorRegs is passed in as a pointer to the number of ColorRegisters * caller has space to hold. GetCMAP sets to the number actually read.*/ STATIC IFFP GetCMAP(GroupContext *ilbmContext,WORD *colorMap,UBYTE *pNColorRegs) { ColorRegister colorReg; LONG nColorRegs; IFFP iffp; nColorRegs = ilbmContext -> ckHdr . ckSize / sizeof(ColorRegister); if(*pNColorRegs < nColorRegs) nColorRegs = *pNColorRegs; *pNColorRegs = nColorRegs; /* Set to the number actually there.*/ while(nColorRegs--) { iffp = IFFReadBytes(ilbmContext,(BYTE *)&colorReg,sizeof(ColorRegister)); CheckIFFP(); *colorMap++ = ((UWORD)(colorReg . red >> 4 ) << 8 ) | ((UWORD)(colorReg . green & 0x0F0)) | ((UWORD)(colorReg . blue >> 4)); } return(IFF_OKAY); } /** GetPrILBM() ************************************************************* * * Called via ReadPicture to handle every PROP encountered in an IFF file. * Reads PROPs ILBM and skips all others. * ****************************************************************************/ STATIC IFFP GetPrILBM(GroupContext *parent) { IFFP iffp; GroupContext propContext; ILBMFrame *ilbmFrame = (ILBMFrame *)parent -> clientFrame; if(parent -> subtype != ID_ILBM) return(IFF_OKAY); /* just continue scanning the file */ iffp = OpenRGroup(parent,&propContext); CheckIFFP(); do { switch(iffp = GetPChunkHdr(&propContext)) { case ID_BMHD: { ilbmFrame -> foundBMHD = TRUE; iffp = GetBMHD(&propContext,&ilbmFrame -> bmHdr); break; } case ID_CMAP: { ilbmFrame -> nColorRegs = maxColorReg; iffp = GetCMAP(&propContext,(WORD *)&ilbmFrame -> colorMap,&ilbmFrame -> nColorRegs); break; } } } while(iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a * subroutine returned IFF_OKAY (no errors). */ CloseRGroup(&propContext); return(iffp == END_MARK ? IFF_OKAY : iffp); } /** GetLiILBM() ************************************************************* * * Called via ReadPicture to handle every LIST encountered in an IFF file. * ****************************************************************************/ STATIC IFFP GetLiILBM(GroupContext *parent) { ILBMFrame newFrame; /* allocate a new Frame */ newFrame = *(ILBMFrame *)parent -> clientFrame; /* copy parent frame */ return(ReadIList(parent,(ClientFrame *)&newFrame)); } /** GetFoANIM() ************************************************************* * * Called via ReadPicture to handle every FORM encountered in an IFF file. * Reads FORMs ILBM and skips all others. * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it * finds no BODY or if it has no BMHD to decode the BODY. * * Once we find a BODY chunk, we'll allocate the BitMap and read the image. * ****************************************************************************/ STATIC IFFP GetFoANIM(GroupContext *parent) { IFFP iffp; GroupContext formContext; ILBMFrame ilbmFrame; /* only used for non-clientFrame fields.*/ /* Handle a non-ILBM FORM. */ if(parent -> subtype != ID_ILBM) { /* Open a non-ILBM FORM and recursively scan it for ILBMs.*/ iffp = OpenRGroup(parent,&formContext); CheckIFFP(); do { iffp = GetF1ChunkHdr(&formContext); if(iffp == IFF_DONE) iffp = IFF_OKAY; } while(iffp >= IFF_OKAY); if(iffp == END_MARK) iffp = IFF_DONE; /* then continue scanning the file */ CloseRGroup(&formContext); return(iffp); } ilbmFrame = *(ILBMFrame *)parent -> clientFrame; iffp = OpenRGroup(parent,&formContext); CheckIFFP(); if(!IFFfileList -> lastframe) { IFFfileList -> lastframe = (struct FrameHD *)AllocMem(sizeof(struct FrameHD),MEMF_PUBLIC|MEMF_CLEAR); IFFfileList -> firstframe = IFFfileList -> lastframe; } else { if(IFFfileList -> lastframe -> next = (struct FrameHD *)AllocMem(sizeof(struct FrameHD),MEMF_PUBLIC|MEMF_CLEAR)) IFFfileList -> lastframe -> next -> prev = IFFfileList -> lastframe; IFFfileList -> lastframe = IFFfileList -> lastframe -> next; } if(!IFFfileList -> lastframe) return(END_MARK); do { switch(iffp = GetFChunkHdr(&formContext)) { case ID_ANHD: { ilbmFrame . foundBMHD = TRUE; if(!(IFFfileList -> lastframe -> anhd = (AnimationHeader *)AllocMem(sizeof(AnimationHeader),MEMF_PUBLIC|MEMF_CLEAR))) { iffp = DOS_ERROR; break; } iffp = GetANHD(&formContext,IFFfileList -> lastframe -> anhd); break; } case ID_BMHD: { ilbmFrame . foundBMHD = TRUE; if(!(IFFfileList -> lastframe -> bmhd = (BitMapHeader *)AllocMem(sizeof(BitMapHeader),MEMF_PUBLIC|MEMF_CLEAR))) { iffp = DOS_ERROR; break; } else { iffp = GetBMHD(&formContext,IFFfileList -> lastframe -> bmhd); if(IFFfileList -> lastframe -> bmhd -> pageHeight < IFFfileList -> lastframe -> bmhd -> h) IFFfileList -> lastframe -> bmhd -> pageHeight = IFFfileList -> lastframe -> bmhd -> h; if(IFFfileList -> lastframe -> bmhd -> pageWidth < IFFfileList -> lastframe -> bmhd -> w) IFFfileList -> lastframe -> bmhd -> pageWidth = IFFfileList -> lastframe -> bmhd -> w; if(IFFfileList -> lastframe -> bmhd -> pageHeight != Screen -> Height || IFFfileList -> lastframe -> bmhd -> pageWidth != Screen -> Width || IFFfileList -> lastframe -> bmhd -> nPlanes != Screen -> RastPort . BitMap -> Depth) iffp = DOS_ERROR; break; } } case ID_CAMG: { ilbmFrame . foundCAMG = TRUE; if(!(IFFfileList -> lastframe -> camg = (CamgChunk *)AllocMem(sizeof(CamgChunk),MEMF_PUBLIC|MEMF_CLEAR))) { iffp = DOS_ERROR; break; } else { iffp = GetCAMG(&formContext,IFFfileList -> lastframe -> camg); break; } } case ID_CMAP: { IFFfileList -> lastframe -> nColorRegs = maxColorReg; /* we have room for this many */ iffp = GetCMAP(&formContext,&IFFfileList -> lastframe -> cmap[0],&IFFfileList -> lastframe -> nColorRegs); break; } case ID_DLTA: /* at this point just read in delta chunk */ case ID_BODY: { if(!ilbmFrame . foundBMHD) return(BAD_FORM); /* No BMHD chunk! */ if(IFFfileList -> lastframe -> bodylength = formContext . ckHdr . ckSize) { if(!(IFFfileList -> lastframe -> body = (ULONG *)AllocMem(IFFfileList -> lastframe -> bodylength,MEMF_PUBLIC|MEMF_CLEAR))) { iffp = END_MARK; break; } IFFReadBytes(&formContext,(BYTE *)IFFfileList -> lastframe -> body,IFFfileList -> lastframe -> bodylength); } break; } case END_MARK: /* No BODY chunk! */ { iffp = IFF_DONE; break; } } } while(iffp >= IFF_OKAY); /* loop if valid ID of ignored chunk or a * subroutine returned IFF_OKAY (no errors). */ if(iffp != IFF_DONE) return(iffp); /* If we get this far, there were no errors. */ CloseRGroup(&formContext); return(iffp); } STATIC IFFP __regargs PreLoadAnimation(BPTR file,ILBMFrame *iFrame) { iFrame -> clientFrame . getList = GetLiILBM; iFrame -> clientFrame . getProp = GetPrILBM; iFrame -> clientFrame . getForm = GetFoANIM; iFrame -> clientFrame . getCat = ReadICat ; /* Initialize the top-level client frame's property settings to the * program-wide defaults. This example just records that we haven't read * any BMHD property or CMAP color registers yet. For the color map, that * means the default is to leave the machine's color registers alone. * If you want to read a property like GRAB, init it here to (0, 0). */ iFrame -> foundBMHD = FALSE; iFrame -> nColorRegs = 0; /* Store a pointer to the client's frame in a global variable so that * GetFoILBM can update client's frame when done. Why do we have so * many frames & frame pointers floating around causing confusion? * Because IFF supports PROPs which apply to all FORMs in a LIST, * unless a given FORM overrides some property. * When you write code to read several FORMs, * it is ssential to maintain a frame at each level of the syntax * so that the properties for the LIST don't get overwritten by any * properties specified by individual FORMs. * We decided it was best to put that complexity into this one-FORM example, * so that those who need it later will have a useful starting place. */ if(IFFfileList = (struct IFFfile *)AllocMem(sizeof(struct IFFfile),MEMF_PUBLIC|MEMF_CLEAR)) return(ReadIFF(file,(ClientFrame *)iFrame)); else return(DOS_ERROR); } VOID ClosePreLoadIFF() { if(IFFfileList) { struct FrameHD *currentframe,*nextframe; currentframe = IFFfileList -> firstframe; while(currentframe) { if(currentframe -> bmhd) FreeMem(currentframe -> bmhd,sizeof(BitMapHeader)); if(currentframe -> anhd) FreeMem(currentframe -> anhd,sizeof(AnimationHeader)); if(currentframe -> camg) FreeMem(currentframe -> camg,sizeof(CamgChunk)); if(currentframe -> body && currentframe -> bodylength) FreeMem(currentframe -> body,currentframe -> bodylength); nextframe = currentframe -> next; FreeMem(currentframe,sizeof(struct FrameHD)); currentframe = nextframe; } FreeMem(IFFfileList,sizeof(struct IFFfile)); IFFfileList = NULL; } } BYTE OpenPreLoadIFF(BPTR file) { ILBMFrame iframe; if(PreLoadAnimation(file,&iframe) != IFF_DONE) { ClosePreLoadIFF(); return(FALSE); } else return(TRUE); }