/***************************************************************** * * Read an ILBM file and display as a screen/window until closed. * Simulated close gadget in upper left corner of window. * Clicking below title bar area toggles screen bar for dragging. * * By Carolyn Scheppner CBM 03/15/86 * * Based on early ShowILBM.c 11/12/85 * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts. * This software is in the public domain. * * >>NOTE<<: This example must be linked with additional IFF rtn files. * See linkage information below. * * The IFF reader portion is essentially a recursive-descent parser. * This program will look into a CAT or LIST to find a FORM ILBM, but it * won't look inside another FORM type for a nested FORM ILBM. * * The display portion is specific to the Commodore Amiga computer. * * Linkage Information: * * FROM LStartup.obj, SeeILBM.o, iffr.o, ilbmr.o, unpacker.o * TO SeeILBM * LIBRARY LC.lib, Amiga.lib * **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "iff/ilbm.h" /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */ #define EXDepth 5 #define maxColorReg (1<1) /* Passed filename via command line */ { filename = argv[1]; } else if ((argc==0)&&(WBenchMsg->sm_NumArgs > 1)) { /* Passed filename via WorkBench */ arg = WBenchMsg->sm_ArgList; arg++; filename = (char *)arg->wa_Name; newLock = (struct FileLock *)arg->wa_Lock; startLock = (struct FileLock *)CurrentDir(newLock); } else if (argc==1) /* From CLI but no filename */ cleanexit("Usage: 'SeeILBM filename'\n"); else /* From WB but no filename */ cleanexit("\nClick ONCE on SeeILBM\nSHIFT and DoubleClick on Pic\n"); if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) cleanexit("Can't open graphics library\n"); if(!(IntuitionBase= (struct IntuitionBase *)OpenLibrary("intuition.library",0))) cleanexit("Can't open graphics library\n"); if(file = Open(filename, MODE_OLDFILE)) { printf("\nCLICK PIC TOP LEFT TO END DISPLAY\n"); printf("CLICK LOWER TO TOGGLE DRAG BAR\n"); Delay(150); /* wait about 3 seconds to give person time to read it */ iffp = ReadPicture(file); Close(file); if (iffp == IFF_DONE) { error = DisplayPic(&ilbmFrame); if(error) cleanexit("Can't open screen or window\n"); TBtoggle = FALSE; /* Title bar toggle */ Done = FALSE; /* Close flag */ while (!Done) { if(1<UserPort->mp_SigBit) chkmsg(); } } else cleanexit(IFFPMessages[-iffp]); } else cleanexit("Picture file not found.\n"); cleanup(); } chkmsg() { while(message=(struct IntuiMessage *)GetMsg(window1->UserPort)) { class = message->Class; code = message->Code; ReplyMsg(message); switch(class) { case MOUSEBUTTONS: if ((code == SELECTDOWN)&& (window1->MouseX < 10)&&(window1->MouseY<10)) { Done = TRUE; } else if ((code == SELECTDOWN)&& (window1->MouseY>10)&&(TBtoggle==FALSE)) { TBtoggle = TRUE; ShowTitle(screen1,TRUE); } else if ((code == SELECTDOWN)&& (window1->MouseY>10)&&(TBtoggle==TRUE)) { TBtoggle = FALSE; ShowTitle(screen1,FALSE); } break; default: printf("Unknown IDCMP message\n"); } } } cleanexit(errstr) char *errstr; { printf("\n %s \n",errstr); cleanup(); if (fromWB) /* Wait so user can read messages */ { printf("\nPRESS RETURN TO CLOSE THIS WINDOW\n"); while ((c=getchar()) != '\n'); } exit(); } cleanup() { /* tBitMap planes were deallocated in DisplayPic() */ if (window1) CloseWindow(window1); if (screen1) CloseScreen(screen1); if (IntuitionBase) CloseLibrary(IntuitionBase); if (GfxBase) CloseLibrary(GfxBase); if (newLock != startLock) CurrentDir(startLock); } /** getBitMap() ********************************************************* * * Open screen or temp bitmap. * Returns ptr destBitMap or 0 = error * *************************************************************************/ struct BitMap *getBitMap(ptilbmFrame) ILBMFrame *ptilbmFrame; { int i, nPlanes, plsize; SHORT sWidth, sHeight, dWidth, dHeight; struct BitMap *destBitMap; sWidth = ptilbmFrame->bmHdr.w; sHeight = ptilbmFrame->bmHdr.h; dWidth = ptilbmFrame->bmHdr.pageWidth; dHeight = ptilbmFrame->bmHdr.pageHeight; nPlanes = MIN(ptilbmFrame->bmHdr.nPlanes, EXDepth); for (i = 0; i < ptilbmFrame->nColorRegs; i++) { allBgColor[i] = ptilbmFrame->colorMap[0]; } ns.Width = dWidth; ns.Height = dHeight; ns.Depth = nPlanes; if (ptilbmFrame->bmHdr.pageWidth <= 320) ns.ViewModes = 0; else ns.ViewModes = HIRES; if (ptilbmFrame->bmHdr.pageHeight > 200) ns.ViewModes |= LACE; if ((screen1 = (struct Screen *)OpenScreen(&ns))==NULL) return(0); vport1 = &screen1->ViewPort; LoadRGB4(vport1, &allBgColor[0], ptilbmFrame->nColorRegs); nw.Width = dWidth; nw.Height = dHeight; nw.Screen = screen1; if ((window1 = (struct Window *)OpenWindow(&nw))==NULL) return(0); ShowTitle(screen1, FALSE); if ((sWidth == dWidth) && (sHeight == dHeight)) { destBitMap = (struct BitMap *)screen1->RastPort.BitMap; } else { InitBitMap( &tBitMap, nPlanes, sWidth, sHeight); plsize = RowBytes(ptilbmFrame->bmHdr.w) * ptilbmFrame->bmHdr.h; if (tBitMap.Planes[0] = (PLANEPTR)AllocMem(nPlanes * plsize, MEMF_CHIP)) { for (i = 1; i < nPlanes; i++) tBitMap.Planes[i] = (PLANEPTR)tBitMap.Planes[0] + plsize*i; destBitMap = &tBitMap; } else { return(0); /* can't allocate temp BitMap */ } } return(destBitMap); /* destBitMap allocated */ } /** DisplayPic() ********************************************************* * * Display loaded bitmap. If tBitMap, first transfer to screen. * *************************************************************************/ DisplayPic(ptilbmFrame) ILBMFrame *ptilbmFrame; { int i, row, byte, nrows, nbytes; struct BitMap *tbp, *sbp; /* temp and screen BitMap ptrs */ UBYTE *tpp, *spp; /* temp and screen plane ptrs */ if (tBitMap.Planes[0]) /* transfer from tBitMap if nec. */ { tbp = &tBitMap; sbp = screen1->RastPort.BitMap; nrows = MIN(tbp->Rows, sbp->Rows); nbytes = MIN(tbp->BytesPerRow, sbp->BytesPerRow); for (i = 0; i < sbp->Depth; i++) { tpp = (UBYTE *)tbp->Planes[i]; spp = (UBYTE *)sbp->Planes[i]; for (row = 0; row < nrows; row++) { tpp = tbp->Planes[i] + (row * tbp->BytesPerRow); spp = sbp->Planes[i] + (row * sbp->BytesPerRow); for (byte = 0; byte < nbytes; byte++) { *spp++ = *tpp++; } } } /* Can now deallocate the temp BitMap */ FreeMem(tBitMap.Planes[0], tBitMap.BytesPerRow * tBitMap.Rows * tBitMap.Depth); } vport1 = &screen1->ViewPort; LoadRGB4(vport1, ptilbmFrame->colorMap, ptilbmFrame->nColorRegs); return(0); } /** GetLiILBM() ********************************************************** * * Called via ReadPicture to handle every LIST encountered in an IFF file. * *************************************************************************/ #if Fancy IFFP GetLiILBM(parent) GroupContext *parent; { ILBMFrame newFrame; /* allocate a new Frame */ newFrame = *(ILBMFrame *)parent->clientFrame; /* copy parent frame */ return( ReadIList(parent, (ClientFrame *)&newFrame) ); } #endif /** GetPrILBM() ********************************************************** * * Called via ReadPicture to handle every PROP encountered in an IFF file. * Reads PROPs ILBM and skips all others. * *************************************************************************/ #if Fancy IFFP GetPrILBM(parent) GroupContext *parent; { /*compilerBug register*/ IFFP iffp; GroupContext propContext; ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame; if (parent->subtype != ID_ILBM) return(IFF_OKAY); /* just continue scaning 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; /* room for this many */ iffp = GetCMAP( &propContext, (WORD *)ilbmFrame->colorMap, &ilbmFrame->nColorRegs); break; } } while (iffp >= IFF_OKAY);/* loop if valid ID of ignored chunk or * subrtn returned IFF_OKAY (no errors).*/ CloseRGroup(&propContext); return(iffp == END_MARK ? IFF_OKAY : iffp); } #endif /** GetFoILBM() ********************************************************** * * 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. * * Modified by C. Scheppner: ilbmFrame moved above main making it * global so main can call DisplayPic() * *************************************************************************/ IFFP GetFoILBM(parent) GroupContext *parent; { IFFP iffp; GroupContext formContext; BYTE buffer[bufSz]; struct BitMap *destBitMap; if (parent->subtype != ID_ILBM) return(IFF_OKAY); /* just continue scaning the file */ ilbmFrame = *(ILBMFrame *)parent->clientFrame; iffp = OpenRGroup(parent, &formContext); CheckIFFP(); do switch (iffp = GetFChunkHdr(&formContext)) { case ID_BMHD: { ilbmFrame.foundBMHD = TRUE; iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr); break; } case ID_CMAP: { ilbmFrame.nColorRegs = maxColorReg; /* we have room for this many */ iffp = GetCMAP(&formContext, (WORD *)ilbmFrame.colorMap, &ilbmFrame.nColorRegs); break; } case ID_BODY: { if (!ilbmFrame.foundBMHD) return(BAD_FORM); /* No BMHD chunk! */ if(destBitMap=(struct BitMap *)getBitMap(&ilbmFrame)) { iffp = GetBODY( &formContext, destBitMap, NULL, &ilbmFrame.bmHdr, buffer, bufSz); if (iffp == IFF_OKAY) iffp = IFF_DONE; /* Eureka */ } else iffp = CLIENT_ERROR; /* not enough RAM for the bitmap */ break; } case END_MARK: { iffp = BAD_FORM; 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); CloseRGroup(&formContext); return(iffp); } /** Notes on extending GetFoILBM ***************************************** * * To read more kinds of chunks, just add clauses to the switch statement. * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to * the switch statement in GetPrILBM, too. * * To read a FORM type that contains a variable number of data chunks--e.g. * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK * case do whatever cleanup you need. * *************************************************************************/ /** ReadPicture() ******************************************************** * * Read a picture from an IFF file, given a file handle open for reading. * * Modified by Carolyn Scheppner CBM 03-86 * iFrame made global (above main) * Close(file) moved to main * *************************************************************************/ IFFP ReadPicture(file) LONG file; { IFFP iffp = IFF_OKAY; #if Fancy iFrame.clientFrame.getList = GetLiILBM; iFrame.clientFrame.getProp = GetPrILBM; #else iFrame.clientFrame.getList = SkipGroup; iFrame.clientFrame.getProp = SkipGroup; #endif iFrame.clientFrame.getForm = GetFoILBM; 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; iffp = ReadIFF(file, (ClientFrame *)&iFrame); return(iffp); }