home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * This is my own program to load a picture into the Workbench screen.
- * To my mind it has one advantage over others of its type -- it does
- * no processing whatsoever to keep the display from being erased. Since
- * it turns the Workbench into a DualPlayfield display, the picture can
- * be displayed at all times and there are some good possibilities for
- * showing images of 1 or 2 planes without disturbing the normal Workbench
- * colours.
- *
- * John Russell 12/31/87
- *
- */
-
- /*
- * PROGRAM NOTES
- * -------------
- *
- * I did a lot of error checking and tracing since this is my first program
- * to ever use IFF. Major errors are always displayed, you can enable
- * picayune tracing and error messages by defining debug(x) to be puts(x).
- * Otherwise the calls to debug and string constants don't take up any space
- * so there's no harm in leaving them in.
- *
- * I hope to check for various 'odd' error conditions in future versions of
- * the program. Among them are:
- *
- * (Y) - Workbench already dualpf or > 2 planes due to DropShadow or similar
- * program
- * (N) - Workbench screen changing size dynamically via lacetogl or similar
- * program (this if I close the window and just leave picture in memory
- * for later de-allocation)
- * (Y) - illegal values read from the picture file; any kind of picture will
- * be handled. If it's 1/2 size or less in a particular axis it will
- * be doubled.
- *
- * Planned options (some of these also are not yet implemented):
- *
- * (Y) - load 1 or 2 bitplane image with true colours, deeper images with
- * bitplanes truncated to 2
- * (Y) - free second bitplane if it isn't needed
- * (Y) - change Workbench background colour to pic background colour or not
- * (Y) - specify colour for background and/or pen #1 via command line
- * (N) - program sets up and exits so as to use minimum memory; picture
- * deleted by invoking program again
- * (N) - specify pattern and/or design to place in background; this should
- * be created by a second, easily created program for maximum
- * flexibility (eg draw sine curves or sloping lines)
- * (N) - specify if image / Workbench screen priority so you could actually
- * overlay the image on top of the Workbench; not important
- * (N) - interactively adjust colours of image screen (cf. the colour program
- * I posted to see how this can be done); right now you can specify
- * 2 of the 4 yourself so I don't consider this important
- *
- * Any options which I can't fit in by 48 hours after I started this program
- * will have to wait 'til a later version but they aren't hard to add in
- * yourself.
- *
- */
-
- /*
- * Credits:
- *
- * IFF read routines adapted from a program by Leo Schwab
- * GetOpt ported from Unix by Adam Levin
- * Dual-playfield code from an example by Jim Mackraz
- *
- * This program is © (Copyright) 1987 John Russell
- *
- * Freely redistributable, donation of $15 or so appreciated if you find this
- * program really neat and use it a lot; any money received will go not to
- * Iran or Central America, but towards some extra memory :-).
- *
- * Also if you send me a disk with rare or hard to find programs, utilities
- * that haven't received wide distribution (maybe some you've written yourself)
- * I will reciprocate with my favourite little-known gems.
- *
- */
-
- /*
- * John Russell
- * 5 Alderdice Place
- * St. John's, Newfoundland
- * Canada A1B 2P8
- * (709) 726-7847
- *
- * E-mail: john13@garfield.uucp
- * john13@garfield.mun.cdn
- *
- */
-
- /* Only tested with Manx 32-bit compilation but I tried as much as possible
- to be 16-bit compatible. */
-
- #include "graphics:tc/tablecloth.h" /* IFF definitions, IntuitionBase etc */
-
- extern char *optarg;
- extern int getopt();
- char *optstring = "b0:1:";
-
- /* for window definition */
-
- ULONG flg = (ACTIVATE | WINDOWCLOSE | NOCAREREFRESH | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH);
- ULONG iflg = (CLOSEWINDOW);
-
- BOOL background_opaque = FALSE;
- BOOL set_pen0 = FALSE;
- BOOL set_pen1 = FALSE;
-
- ULONG pen0, pen1;
-
- struct bmhd bmhd; /* official structure name is BitMapHeader */
- struct ChunkHeader chunk;
-
- /* need to make these global so I can _abort() */
-
- FILE *fp=NULL;
- struct Window *window = NULL;
- struct Screen *wbscreen;
- struct RasInfo *rinfo2 = NULL; /* second playfield rasinfo ... */
- struct BitMap *bmap2 = NULL; /* ... and bitmap */
- struct RastPort *rport2 = NULL; /* for rendering into bmap2 */
- struct ViewPort *vp;
- struct ColorMap *map;
- BOOL it_is_done = FALSE; /* success flag */
- ULONG old_wbcolour,background_colour;
- WORD exitval = 0;
- int actual_planes = 2;
-
- /*
- * Possible arguments are:
- * -b ; change the background colour on Workbench screen to the
- * background colour from the file
- * -0 hhh ; background colour set to RGB value in hex
- * -1 hhh ; pen 1 set to RGB value in hex
- *
- * eg. tablecloth -0 666 -1 000 sample.picture
- *
- * Loads "sample picture", the picture will be displayed as
- * black-on-gray. -0 option forces -b automatically.
- *
- */
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- struct IntuiMessage *msg;
- char *picname;
- ULONG class;
- short count;
- UBYTE *ptr;
-
- /* IFF variables */
-
- long chunk_type;
- long viewmodes; /* not used in this version */
- BOOL got_body = FALSE, got_bmhd = FALSE;
-
- if (argc < 2)
- {
- puts("Need a picture name for an argument.");
- _abort();
- }
-
- parse_args(argc,argv);
-
- picname = argv[argc-1]; /* final argument */
-
- if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L)))
- {
- puts("NO INTUITION LIBRARY");
- _abort();
- }
-
- if (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
- {
- puts("NO GRAPHICS LIBRARY");
- _abort();
- }
-
- /* get a window on the workbench */
-
- if (!(window = getNewWind(220, 0, 360, 10, flg, iflg)))
- {
- puts("Can't open window");
- _abort();
- }
-
- debug("Opened window OK");
-
- /* ------ Add a second playfield for Workbench ------------ */
-
-
- wbscreen = window->WScreen; /* find it */
-
- /* test for voodoo such as DropShadow which already has added bitplane(s) */
-
- if (wbscreen->BitMap.Depth > 2)
- {
- puts("Workbench has too many bitplanes for me to work");
- _abort();
- }
-
- /* allocate second playfield's rasinfo, bitmap, and bitplane */
-
- if (!(rinfo2 = (struct RasInfo *)
- AllocMem(sizeof(struct RasInfo), MEMF_PUBLIC|MEMF_CLEAR)))
- {
- debug("RasInfo structure allocation failed");
- _abort();
- }
-
- debug("Allocated RasInfo OK");
-
- if (!(bmap2=(struct BitMap *)AllocMem(sizeof(struct BitMap),MEMF_PUBLIC|MEMF_CLEAR)))
- {
- debug("Bitmap structure allocation failed");
- _abort();
- }
-
- debug("Allocated BitMap OK");
-
- InitBitMap(bmap2, 2, wbscreen->Width, wbscreen->Height);
-
- debug("Initialized BitMap OK");
-
- /* we'll use 2 planes. */
-
- /* the (UWORD *) for AllocRaster is JimM's. I left it there and inserted the other to shut the compiler up. */
-
- if (! ( ((UWORD *)(bmap2->Planes[0])=(UWORD *)AllocRaster(wbscreen->Width, wbscreen->Height)) && ((UWORD *)(bmap2->Planes[1])=(UWORD *)AllocRaster(wbscreen->Width, wbscreen->Height))))
- {
- puts("AllocRaster failed while getting bitplanes");
- _abort();
- }
-
- debug("AllocRaster went OK");
-
- /* get a rastport, and set it up for rendering into bmap2 */
- if (!(rport2 = (struct RastPort *)
- AllocMem(sizeof (struct RastPort), MEMF_PUBLIC)))
- {
- puts("alloc rastport failed");
- _abort();
- }
-
- debug("Rastport structure allocated OK");
-
- InitRastPort(rport2);
-
- debug("Initialized rport structure OK");
-
- rport2->BitMap = bmap2;
- SetRast(rport2, 0);
-
- /* manhandle viewport: install second playfield and change modes */
- Forbid();
-
- /* install my bitmap in my rasinfo */
- rinfo2->BitMap = bmap2;
-
- /* install rinfo for viewport's second playfield */
- wbscreen->ViewPort.RasInfo->Next = rinfo2;
-
- /* convert viewport */
- wbscreen->ViewPort.Modes |= DUALPF;
-
- it_is_done = TRUE;
-
- Permit();
-
- debug("Installed playfield, modes changed OK");
-
- /* put viewport changed into effect */
- MakeScreen(wbscreen);
- RethinkDisplay();
-
- vp = &wbscreen->ViewPort; /* need these for colour operations */
- map = vp->ColorMap;
-
- debug("Second playfield is now enabled.");
-
- /*
- * Now I load in the picture to the already-created rastport. The picture
- * load routine ought to deal with any size or depth picture. If the
- * picture has more than 4 colours the extra bitplanes are ignored.
- *
- * John Russell 12/31/87
- *
- */
-
- if (! (fp=fopen(picname,"r")))
- {
- printf("Unable to open picture %s.\n",picname);
- _abort();
- }
-
- debug("Opened picture file OK");
-
- if (!good_pict(fp))
- {
- puts("This is not an IFF picture I can recognize.");
- _abort();
- }
-
- debug("Picture is valid IFF");
-
- /* ,
- * Tres bummer! I can hack together an IFF reader that I feel comfortable
- * with faster than I can adapt any of the official code examples.
- *
- * If I have anything to do with it, that won't be the situation much
- * longer. Look for the IFF equivalents to OpenWindow and CloseWindow
- * (ie one highly-structured call does all the work) coming soon.
- *
- * The only IFF code I plagiarized was courtesy of Leo Schwab (much of the
- * header stuff and the load-bitmap outline). Please let me know of any
- * picture types you find cause problems for this program so I can correct
- * the situation.
- *
- */
-
- /*
- * We have to get the chunks in a certain order; this is:
- *
- * - FORM
- * - ILBM (not really a chunk, although it should be for consistency)
- * - CAMG and CMAP can go anywhere in this section
- * - BMHD
- * - BODY
- *
- */
-
- while (chunk_type = get_chunk(fp))
- {
- switch(chunk_type)
- {
- case CAMG:
- /* this is not actually used, but might be by a future version */
- debug("Read a CAMG chunk");
- fread(&viewmodes,(int)chunk.chunksize,1,fp);
- break;
-
- case BMHD:
- debug("Read a BMHD chunk");
- fread(&bmhd,(int)chunk.chunksize,1,fp);
- got_bmhd = TRUE;
- break;
-
- /* have to provide some way to override these colours if user chooses */
-
- case CMAP:
- {
- register UBYTE *ctable;
- register UWORD *cmap;
- register long i,n;
-
- debug("Read a CMAP chunk");
-
- if (!(ctable = AllocMem (chunk.chunksize, NULL)))
- {
- debug("Colourtable alloc failed");
- _abort();
- }
-
- fread (ctable, (int) chunk.chunksize, 1, fp);
-
- if (!(cmap = AllocMem(chunk.chunksize * 2 / 3, NULL)))
- {
- debug("Colourmap alloc failed");
- _abort();
- }
-
- /* NB: IFF stores more colour info, so we must get only 4 bits for each of RGB */
- /* Here is how you could load them in from a colormap. */
- /* for (i = n = 0; i < (1 << actual_planes); i++, n+=3) */
- /* cmap[i] = ((ctable[n] >> 4) << 8) + ((ctable[n+1] >> 4) << 4) + (ctable[n+2] >> 4); */
- /* LoadRGB4 (viewport, cmap, (long) (1 << actual_planes)); */
-
- /* However I only want a few, and in an already-setup viewport. */
-
- for (i = n = 0; i < (1 << actual_planes); i++, n+=3)
- SetRGB4(vp, i+8, (long)(ctable[n] >> 4), (long)(ctable[n+1] >> 4), (long)(ctable[n+2] >> 4));
-
- FreeMem (cmap, chunk.chunksize * 2 / 3);
- FreeMem (ctable, chunk.chunksize);
-
- }
- break;
-
- case BODY:
- if (got_bmhd)
- {
- /* this is the big "read picture into memory" part */
- debug("Reading body chunk");
- if (!get_body(fp,&bmhd,rport2->BitMap))
- {
- puts("Error while reading bitmap");
- _abort();
- }
- got_body = TRUE;
- }
- else
- {
- puts("Body chunk is out of order!");
- _abort();
- }
- break;
-
- default:
- debug("Read unknown chunk type");
- fseek(fp,chunk.chunksize,1);
- break;
- }
- }
- debug("Finished with all chunks");
-
- if (got_body == FALSE)
- {
- puts("Hey, no bitmap image present!");
- _abort();
- }
-
- /* now adjust colours if need be */
-
- if (background_opaque)
- {
- old_wbcolour = (ULONG)GetRGB4(map,0);
-
- if (set_pen0)
- {
- SetRGB4(vp, 0, (pen0 & 0xf00) >> 8, (pen0 & 0x0f0) >> 4, (pen0 & 0x00f));
- }
- else
- {
- background_colour = (ULONG)GetRGB4(map, 8);
- SetRGB4(vp, 0, (background_colour & 0xf00) >> 8, (background_colour & 0x0f0) >> 4, (background_colour & 0x00f));
- }
- }
-
- if (set_pen1)
- {
- SetRGB4(vp, 9, (pen1 & 0xf00) >> 8, (pen1 & 0x0f0) >> 4, (pen1 & 0x00f));
- }
-
- if (wbscreen->Width >= (bmhd.w << 1))
- {
- debug("Doubling picture horizontally");
- for (count = wbscreen->Width; count; count -= 2)
- {
- ClipBlit(rport2,count/2,0,rport2,count-1,0,1,wbscreen->Height,0xc0);
- ClipBlit(rport2,count/2,0,rport2,count-2,0,1,wbscreen->Height,0xc0);
- }
- }
-
- if (wbscreen->Height >= (bmhd.h << 1))
- {
- debug("Doubling picture vertically");
- for (count = wbscreen->Height; count; count -= 2)
- {
- ClipBlit(rport2,0,count/2,rport2,0,count-1,wbscreen->Width,1,0xc0);
- ClipBlit(rport2,0,count/2,rport2,0,count-2,wbscreen->Width,1,0xc0);
- }
- }
-
- if (bmhd.nplanes == 1) /* don't need second plane for monochrome image */
- {
- Forbid();
- if (ptr = bmap2->Planes[1])
- {
- bmap2->Planes[1] = NULL;
- bmap2->Depth = 1;
- FreeRaster(ptr, wbscreen->Width, wbscreen->Height);
- }
- Permit();
-
- /* put viewport changed into effect */
- MakeScreen(wbscreen);
- RethinkDisplay();
- }
-
- FOREVER
- {
- if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL)
- {
- Wait( 1 << window->UserPort->mp_SigBit);
- continue;
- }
-
- class = msg->Class;
- ReplyMsg(msg);
-
- switch (class)
- {
- case CLOSEWINDOW:
- debug("event CLOSEWINDOW");
- _abort();
- break;
- default:
- debug("unknown event class");
- break;
- }
- }
-
- QUIT:
-
- debug("Arrived at QUIT routine");
-
- _abort();
- }
-
- _abort() /* so CTRL-c will be handled cleanly; unfortunately I have to declare a lot of variables globally to make it work */
- {
- /* clean up dual-playfield trick */
-
- if (it_is_done)
- {
- debug("Deleting second playfield");
-
- Forbid();
- wbscreen->ViewPort.RasInfo->Next = NULL;
- wbscreen->ViewPort.Modes &= ~DUALPF;
- Permit();
- MakeScreen(wbscreen);
- RethinkDisplay();
- }
-
- if (background_opaque)
- {
- SetRGB4(vp, 0, (old_wbcolour & 0xf00) >> 8, (old_wbcolour & 0x0f0) >> 4, (old_wbcolour & 0x00f));
- }
-
- if (rport2) FreeMem(rport2, sizeof (struct RastPort));
-
- if (bmap2)
- {
- if (bmap2->Planes[0])
- {
- FreeRaster(bmap2->Planes[0], wbscreen->Width, wbscreen->Height);
- }
-
- if (bmap2->Planes[1])
- {
- FreeRaster(bmap2->Planes[1], wbscreen->Width, wbscreen->Height);
- }
-
- FreeMem(bmap2, sizeof (struct BitMap));
- }
-
- if (rinfo2) FreeMem(rinfo2, sizeof (struct RasInfo));
- if (fp) fclose(fp);
- if (window) CloseWindow(window);
- if (GfxBase) CloseLibrary(GfxBase);
- if (IntuitionBase) CloseLibrary(IntuitionBase);
-
- exit (exitval);
- }
-
- parse_args(ac,av)
- int ac;
- char **av;
- {
- char option;
-
- debug("Parsing arguments");
-
- while((option = getopt(ac, av, optstring)) != EOF)
- {
- debug("Got argument");
-
- switch(toupper(option))
- {
- case 'B':
- debug("Background will be opaque");
- background_opaque = TRUE;
- break;
-
- case '0':
- debug("Set background colour");
- set_pen0 = TRUE;
- background_opaque = TRUE;
- sscanf(optarg,"%x",&pen0);
- break;
-
- case '1':
- debug("Set pen #1 colour");
- set_pen1 = TRUE;
- sscanf(optarg,"%x",&pen1);
- break;
-
- default:
- debug("Unknown argument");
- break;
- }
- }
- }
-
-