/* * Display.c * 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. * Handles normal and HAM ILBM's * Does automatic color cycling (see note below) * Accepts optional 2nd CLI arg for display time in seconds * * By Carolyn Scheppner CBM 03/15/86 * * Modified 09/02/86 - Only global frame is iFrame * Use message->MouseX and Y * Wait() for IDCMP * Modified 10/15/86 - For HAM * Name changed from SeeILBM to ViewILBM * Modified 11/01/86 - Revised for linkage with myreadpict.c * Modified 11/18/86 - For Astartup ... Amiga.lib, LC.lib linkage * Modified 12/12/86 - Added color cycling at request of Mimetics * Modified 01/06/87 - Tab toggles cycling * Modified 03/03/87 - Recognizes RNG_NORATE (36) as non-active DP CRNG * Changed name to Display * Modified 03/13/87 - Accepts display time in seconds as 2nd CLI arg * * This viewer automatically cycles any ILBM that contains cycling * chunks (CCRT or CRNG) which are marked as active and do not * have a CRNG cycle rate of 36. (To DPaint, rate 36 = don't cycle) * Note that by default, DPaint saves its pics with CRNG (cycling) * chunks flagged as active and with a rate not equal to 36. * This can cause this viewer to cycle DPaint pics which were * not meant to be cycled. To de-activate the CRNG chunks in * a DPaint pic, either resave the pic after setting the cycle * speed for each range to the lowest position, or use the * "uncycle" program. (usage: uncycle DPaintPicName) * * * Based on ShowILBM.c, readpict.c 1/86 * 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 display portion is specific to the Commodore Amiga computer. * * Linkage Information: * (NOTE: All modules including iff stuff compiled with -v on LC2) * * FROM AStartup.obj,Display.o,myreadpict.o,iffr.o,ilbmr.o,unpacker.o * TO Display * LIBRARY Amiga.lib, LC.lib * */ #include #include #include #include #include #include #include #include #include "iff/ilbm.h" #include "myreadpict.h" /* For wbStdio rtns */ extern LONG stdin, stdout, stderr; /* in Astartup.obj */ char conSpec[] = "CON:0/40/640/140/"; BOOL wbHasStdio = NULL; /* general usage pointers */ struct GfxBase *GfxBase; struct IntuitionBase *IntuitionBase; struct IntuiMessage *message; /* Globals for displaying an image */ struct Screen *screen1; struct Window *window1; struct RastPort *rport1; struct ViewPort *vport1; struct BitMap tBitMap; /* Temp BitMap struct for small pics */ /* For WorkBench startup */ extern struct WBStartup *WBenchMsg; BOOL fromWB; struct FileLock *startLock, *newLock; /* Other globals */ int i, error; BYTE c; BOOL TBtoggle, Done; ULONG signals, wSig, class, code, pBytes; SHORT mouseX, mouseY; char u1[] = "\n>>> Display <<< v1 C. Scheppner CBM 03/87\n"; char u2a[] = "\nUsage: Display ilbmfile [time]\n"; char u2b[] = "\nUsage: Click this icon, SHIFT and DoubleClick on pic\n"; char u3[] = "Click toggles bar, Tab toggles cycling, Close upper left\n"; /* Structures for new Screen, new Window */ struct TextAttr TextFont = { "topaz.font", /* Font Name */ TOPAZ_EIGHTY, /* Font Height */ FS_NORMAL, /* Style */ FPF_ROMFONT, /* Preferences */ }; struct NewScreen ns = { 0, 0, /* LeftEdge and TopEdge */ 0, 0, /* Width and Height */ 0, /* Depth */ 1, 0, /* DetailPen and BlockPen */ NULL, /* Special display modes */ CUSTOMSCREEN, /* Screen Type */ &TextFont, /* Use my font */ " <- Close here after clicking below", /* Title */ NULL, /* No gadgets yet */ NULL, /* Ptr to CustomBitmap */ }; struct NewWindow nw = { 0, 0, /* LeftEdge and TopEdge */ 0, 0, /* Width and Height */ -1, -1, /* DetailPen and BlockPen */ MOUSEBUTTONS|VANILLAKEY, /* IDCMP Flags */ ACTIVATE |BACKDROP |BORDERLESS, /* Flags */ NULL, NULL, /* Gadget and Image pointers */ NULL, /* Title string */ NULL, /* Put Screen ptr here */ NULL, /* SuperBitMap pointer */ 0, 0, /* MinWidth and MinHeight */ 0, 0, /* MaxWidth and MaxHeight */ CUSTOMSCREEN, /* Type of window */ }; USHORT allBlack[maxColorReg] = {0}; /* For alloc to define new pointer */ #define PDATASZ 12 UWORD *pdata; #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif MIN extern char *IFFPMessages[]; ILBMFrame iFrame; /* my global frame */ /* Cycle Task stuff */ #define CYCLETIME 16384L #define REVERSE 0x02 #define ACTIVE 0x01 extern VOID cycleTask(); char *cyTaskName = "v2cyTask"; struct Task *cyTask; /* Data shared with cycleTask */ CrngChunk *cyCrngs; struct ViewPort *cyVport; int cyRegs, cyCnt; USHORT cyMap[maxColorReg]; LONG cyClocks[maxCycles]; LONG cyRates[maxCycles]; BOOL CycleOn, PrepareToDie; /* For optional time delay */ struct Task *mainTask; BOOL TimerOn; LONG tSigNum = -1; ULONG tSig, dTimer; /*****************************************************************/ main(argc, argv) int argc; char **argv; { LONG file; IFFP iffp = NO_FILE; struct WBArg *arg; char *filename; fromWB = (argc==0) ? TRUE : FALSE; TimerOn = FALSE; if((argc>1)&&(*argv[1] != '?')) /* Passed filename via command line */ { filename = argv[1]; if(argc==3) { TimerOn = TRUE; dTimer = 60 * atoi(argv[2]); } } 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 /* From WB or CLI, no filename or ? */ { usage(); cleanexit(" "); /* Space forces my wait for keypress on WB exit */ } if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) cleanexit("Can't open graphics"); if(!(IntuitionBase= (struct IntuitionBase *)OpenLibrary("intuition.library",0))) cleanexit("Can't open intuition"); if(!(file = Open(filename, MODE_OLDFILE))) cleanexit("Picture file not found"); iffp = myReadPicture(file,&iFrame); Close(file); if (!(iffp == IFF_DONE)) cleanexit("Not an IFF ILBM"); error = DisplayPic(&iFrame); if(error) cleanexit("Can't open screen or window"); if(pdata = (UWORD *)AllocMem(PDATASZ,MEMF_CHIP|MEMF_CLEAR)) { pdata[2] = 0x8000; /* 1 pixel */ SetPointer(window1,pdata,1,16,0,0); } /* Set up cycle/timer task */ mainTask = (struct Task *)FindTask(NULL); if((tSigNum = AllocSignal(-1)) == -1) cleanexit("Can't alloc timerSig"); tSig = 1 << tSigNum; initCycle(&iFrame,vport1); cyTask = (struct Task *)CreateTask(cyTaskName,0,cycleTask,4000); if(!cyTask) cleanexit("Can't create cycling task"); CycleOn = TRUE; TBtoggle = FALSE; /* Title bar toggle */ Done = FALSE; /* Close flag */ wSig = 1<UserPort->mp_SigBit; tSig = 1<crngChunks; cyVport = vp; cyRegs = ptFrame->nColorRegs; cyCnt = ptFrame->cycleCnt; for(k=0; kcolorMap[k]; } /* Init Rates and Clocks */ for(k=0; k= CYCLETIME) { Cycled = TRUE; cyClocks[k] -= CYCLETIME; low = cyCrngs[k].low; high= cyCrngs[k].high; if(cyCrngs[k].active & REVERSE) /* Reverse cycle */ { cyTmp = cyMap[low]; for(i=low,j=low+1; i < high; i++,j++) { cyMap[i] = cyMap[j]; } cyMap[high] = cyTmp; } else /* Forward cycle */ { cyTmp = cyMap[high]; for(i=high,j=high-1; i > low; i--,j--) { cyMap[i] = cyMap[j]; } cyMap[low] = cyTmp; } } } } if(Cycled) { LoadRGB4(cyVport,cyMap,cyRegs); } } if(TimerOn) { if(--dTimer == 0) Signal(mainTask,tSig); } } PrepareToDie = FALSE; while(TRUE); /* Busy wait to die */ } chkmsg() { while(message=(struct IntuiMessage *)GetMsg(window1->UserPort)) { class = message->Class; code = message->Code; mouseX = message->MouseX; mouseY = message->MouseY; ReplyMsg(message); switch(class) { case MOUSEBUTTONS: if ((code == SELECTDOWN)&& (mouseX < 10)&&(mouseY<10)) { Done = TRUE; } else if ((code == SELECTDOWN)&& ((mouseY>10)||(mouseX>10))&& (TBtoggle==FALSE)) { TBtoggle = TRUE; ShowTitle(screen1,TRUE); ClearPointer(window1); } else if ((code == SELECTDOWN)&& (mouseY>10)&&(TBtoggle==TRUE)) { TBtoggle = FALSE; ShowTitle(screen1,FALSE); SetPointer(window1,pdata,1,16,0,0); } break; case VANILLAKEY: if(code==0x09) /* Tab toggles Cycle */ { if(CycleOn) { CycleOn = FALSE; WaitTOF(); /* Make sure cyTask saw FALSE */ WaitBOVP(vport1); LoadRGB4(vport1,iFrame.colorMap,maxColorReg); } else { initCycle(&iFrame,vport1); CycleOn = TRUE; } } break; default: break; } } } usage() { if ((fromWB)&&(! wbHasStdio)) wbHasStdio = openStdio(conSpec); if ((!fromWB)||(wbHasStdio)) { Write(stdout,u1,strlen(u1)); if(!fromWB) Write(stdout,u2a,strlen(u2a)); else Write(stdout,u2b,strlen(u2b)); Write(stdout,u3,strlen(u3)); } } cleanexit(s) char *s; { if (*s) { if ((fromWB)&&(! wbHasStdio)) wbHasStdio = openStdio(conSpec); if ((!fromWB)||(wbHasStdio)) { Write(stdout,s,strlen(s)); Write(stdout,"\n",1); } if (wbHasStdio) { Write(stdout,"\nPRESS RETURN TO EXIT\n",22); while (getchar() != '\n'); } } cleanup(); if (wbHasStdio) closeStdio(); exit(); } cleanup() { if(cyTask) { CycleOn = FALSE; PrepareToDie = TRUE; while(PrepareToDie); DeleteTask(cyTask); } /* Free timer signal */ if (tSigNum > -1) FreeSignal(tSigNum); /* Note - tBitMap planes were deallocated in DisplayPic() */ if (window1) { while(message=(struct IntuiMessage *)GetMsg(window1->UserPort)) { ReplyMsg(message); } CloseWindow(window1); } if (screen1) CloseScreen(screen1); if (pdata) FreeMem(pdata,PDATASZ); if (IntuitionBase) CloseLibrary(IntuitionBase); if (GfxBase) CloseLibrary(GfxBase); if (newLock != startLock) CurrentDir(startLock); } strlen(s) char *s; { int i = 0; while(*s++) i++; return(i); } /** 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); ns.Width = dWidth; ns.Height = dHeight; ns.Depth = nPlanes; if (ptilbmFrame->foundCAMG) { ns.ViewModes = ptilbmFrame->camgChunk.ViewModes; } else { if (ptilbmFrame->bmHdr.pageWidth <= 320) ns.ViewModes = 0; else ns.ViewModes = HIRES; if (ptilbmFrame->bmHdr.pageHeight > 256) ns.ViewModes |= LACE; } if ((screen1 = (struct Screen *)OpenScreen(&ns))==NULL) return(0); vport1 = &screen1->ViewPort; LoadRGB4(vport1, &allBlack[0], ptilbmFrame->nColorRegs); if((ptilbmFrame->camgChunk.ViewModes)&(HAM)) setHam(screen1,FALSE); nw.Width = dWidth; nw.Height = dHeight; nw.Screen = screen1; if ((window1 = (struct Window *)OpenWindow(&nw))==NULL) { CloseScreen(screen1); screen1 = 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 { CloseWindow(window1); window1 = NULL; CloseScreen(screen1); screen1 = NULL; 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); if((ptilbmFrame->camgChunk.ViewModes)&(HAM)) setHam(screen1,TRUE); return(0); } /* setHam --- For toggling HAM so HAM pic invisible while loading */ setHam(scr,toggle) struct Screen *scr; BOOL toggle; { struct ViewPort *vp; struct View *v; vp = &(scr->ViewPort); v = (struct View *)ViewAddress(); Forbid(); if(toggle) { v->Modes |= HAM; vp->Modes |= HAM; } else { v->Modes &= ~HAM; vp->Modes &= ~HAM; } MakeScreen(scr); RethinkDisplay(); Permit(); } /* wbStdio.c --- Open an Amiga stdio window under workbench * For use with AStartup.obj */ openStdio(conspec) char *conspec; { LONG wfile; struct Process *proc; struct FileHandle *handle; if (wbHasStdio) return(1); if (!(wfile = Open(conspec,MODE_NEWFILE))) return(0); stdin = wfile; stdout = wfile; stderr = wfile; handle = (struct FileHandle *)(wfile << 2); proc = (struct Process *)FindTask(NULL); proc->pr_ConsoleTask = (APTR)(handle->fh_Type); proc->pr_CIS = (BPTR)stdin; proc->pr_COS = (BPTR)stdout; return(1); } closeStdio() { struct Process *proc; struct FileHandle *handle; if (! wbHasStdio) return(0); if (stdin > 0) Close(stdin); stdin = -1; stdout = -1; stderr = -1; handle = (struct FileHandle *)(stdin << 2); proc = (struct Process *)FindTask(NULL); proc->pr_ConsoleTask = NULL; proc->pr_CIS = NULL; proc->pr_COS = NULL; wbHasStdio = NULL; }