home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 145.lha / TableCloth / tablecloth.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-21  |  15.0 KB  |  599 lines

  1.  
  2. /*
  3.  *  This is my own program to load a picture into the Workbench screen.
  4.  *  To my mind it has one advantage over others of its type -- it does
  5.  *  no processing whatsoever to keep the display from being erased. Since
  6.  *  it turns the Workbench into a DualPlayfield display, the picture can
  7.  *  be displayed at all times and there are some good possibilities for
  8.  *  showing images of 1 or 2 planes without disturbing the normal Workbench
  9.  *  colours.
  10.  *
  11.  *  John Russell    12/31/87
  12.  *
  13.  */
  14.  
  15. /*
  16.  *  PROGRAM NOTES
  17.  *  -------------
  18.  *
  19.  *  I did a lot of error checking and tracing since this is my first program
  20.  *  to ever use IFF. Major errors are always displayed, you can enable
  21.  *  picayune tracing and error messages by defining debug(x) to be puts(x).
  22.  *  Otherwise the calls to debug and string constants don't take up any space
  23.  *  so there's no harm in leaving them in.
  24.  *
  25.  *  I hope to check for various 'odd' error conditions in future versions of
  26.  *  the program. Among them are:
  27.  *
  28.  *  (Y) - Workbench already dualpf or > 2 planes due to DropShadow or similar
  29.  *      program
  30.  *  (N) - Workbench screen changing size dynamically via lacetogl or similar
  31.  *      program (this if I close the window and just leave picture in memory
  32.  *      for later de-allocation)
  33.  *  (Y) - illegal values read from the picture file; any kind of picture will
  34.  *      be handled. If it's 1/2 size or less in a particular axis it will
  35.  *      be doubled.
  36.  *
  37.  *  Planned options (some of these also are not yet implemented):
  38.  *
  39.  *  (Y) - load 1 or 2 bitplane image with true colours, deeper images with
  40.  *      bitplanes truncated to 2
  41.  *  (Y) - free second bitplane if it isn't needed
  42.  *  (Y) - change Workbench background colour to pic background colour or not
  43.  *  (Y) - specify colour for background and/or pen #1 via command line
  44.  *  (N) - program sets up and exits so as to use minimum memory; picture
  45.  *      deleted by invoking program again
  46.  *  (N) - specify pattern and/or design to place in background; this should
  47.  *      be created by a second, easily created program for maximum
  48.  *      flexibility    (eg draw sine curves or sloping lines)
  49.  *  (N) - specify if image / Workbench screen priority so you could actually
  50.  *      overlay the image on top of the Workbench; not important
  51.  *  (N) - interactively adjust colours of image screen (cf. the colour program
  52.  *      I posted to see how this can be done); right now you can specify
  53.  *      2 of the 4 yourself so I don't consider this important
  54.  *
  55.  *  Any options which I can't fit in by 48 hours after I started this program
  56.  *  will have to wait 'til a later version but they aren't hard to add in
  57.  *  yourself.
  58.  *
  59.  */
  60.  
  61. /*
  62.  *  Credits:
  63.  *
  64.  *  IFF read routines adapted from a program by Leo Schwab
  65.  *  GetOpt ported from Unix by Adam Levin
  66.  *  Dual-playfield code from an example by Jim Mackraz
  67.  *
  68.  *  This program is © (Copyright) 1987 John Russell
  69.  *
  70.  *  Freely redistributable, donation of $15 or so appreciated if you find this
  71.  *  program really neat and use it a lot; any money received will go not to
  72.  *  Iran or Central America, but towards some extra memory :-).
  73.  *
  74.  *  Also if you send me a disk with rare or hard to find programs, utilities
  75.  *  that haven't received wide distribution (maybe some you've written yourself)
  76.  *  I will reciprocate with my favourite little-known gems.
  77.  *
  78.  */
  79.  
  80. /*
  81.  *  John Russell
  82.  *  5 Alderdice Place
  83.  *  St. John's, Newfoundland
  84.  *  Canada  A1B 2P8
  85.  *  (709) 726-7847
  86.  *
  87.  *  E-mail: john13@garfield.uucp
  88.  *        john13@garfield.mun.cdn
  89.  *
  90.  */
  91.  
  92. /*  Only tested with Manx 32-bit compilation but I tried as much as possible
  93.     to be 16-bit compatible. */
  94.  
  95. #include "graphics:tc/tablecloth.h" /* IFF definitions, IntuitionBase etc */
  96.  
  97. extern char *optarg;
  98. extern int getopt();
  99. char *optstring = "b0:1:";
  100.  
  101. /* for window definition */
  102.  
  103. ULONG flg = (ACTIVATE | WINDOWCLOSE | NOCAREREFRESH | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH);
  104. ULONG iflg = (CLOSEWINDOW);
  105.  
  106. BOOL background_opaque = FALSE;
  107. BOOL set_pen0 = FALSE;
  108. BOOL set_pen1 = FALSE;
  109.  
  110. ULONG pen0, pen1;
  111.  
  112. struct bmhd bmhd;   /* official structure name is BitMapHeader */
  113. struct ChunkHeader chunk;
  114.  
  115. /* need to make these global so I can _abort() */
  116.  
  117. FILE *fp=NULL;
  118. struct Window *window = NULL;
  119. struct Screen *wbscreen;
  120. struct RasInfo *rinfo2 = NULL;        /* second playfield rasinfo ... */
  121. struct BitMap  *bmap2 = NULL;        /* ... and bitmap            */
  122. struct RastPort *rport2 = NULL;     /* for rendering into bmap2     */
  123. struct ViewPort *vp;
  124. struct ColorMap *map;
  125. BOOL it_is_done = FALSE;        /* success flag            */
  126. ULONG old_wbcolour,background_colour;
  127. WORD exitval = 0;
  128. int actual_planes = 2;
  129.  
  130. /*
  131.  *  Possible arguments are:
  132.  *    -b    ; change the background colour on Workbench screen to the
  133.  *          background colour from the file
  134.  *    -0 hhh    ; background colour set to RGB value in hex
  135.  *    -1 hhh    ; pen 1 set to RGB value in hex
  136.  *
  137.  *  eg. tablecloth -0 666 -1 000 sample.picture
  138.  *
  139.  *  Loads "sample picture", the picture will be displayed as
  140.  *  black-on-gray. -0 option forces -b automatically.
  141.  *
  142.  */
  143.  
  144. main(argc,argv)
  145. int argc;
  146. char **argv;
  147. {
  148.     struct  IntuiMessage *msg;
  149.     char *picname;
  150.     ULONG class;
  151.     short count;
  152.     UBYTE *ptr;
  153.  
  154. /* IFF variables */
  155.  
  156.     long chunk_type;
  157.     long viewmodes;    /* not used in this version */
  158.     BOOL got_body = FALSE, got_bmhd = FALSE;
  159.  
  160.     if (argc < 2)
  161.     {
  162.     puts("Need a picture name for an argument.");
  163.     _abort();
  164.     }
  165.  
  166.     parse_args(argc,argv);
  167.  
  168.     picname = argv[argc-1];    /* final argument */
  169.  
  170.     if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L)))
  171.     {
  172.     puts("NO INTUITION LIBRARY");
  173.     _abort();
  174.     }
  175.  
  176.     if (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
  177.     {
  178.     puts("NO GRAPHICS LIBRARY");
  179.     _abort();
  180.     }
  181.  
  182.     /* get a window on the workbench */
  183.  
  184.     if (!(window = getNewWind(220, 0, 360, 10, flg, iflg)))
  185.     {
  186.     puts("Can't open window");
  187.     _abort();
  188.     }
  189.  
  190.     debug("Opened window OK");
  191.  
  192.     /* ------ Add a second playfield for Workbench ------------ */
  193.  
  194.  
  195.     wbscreen = window->WScreen;     /* find it */
  196.  
  197.     /* test for voodoo such as DropShadow which already has added bitplane(s) */
  198.  
  199.     if (wbscreen->BitMap.Depth > 2)
  200.     {
  201.     puts("Workbench has too many bitplanes for me to work");
  202.     _abort();
  203.     }
  204.  
  205.     /* allocate second playfield's rasinfo, bitmap, and bitplane */
  206.  
  207.     if (!(rinfo2 = (struct RasInfo *)
  208.     AllocMem(sizeof(struct RasInfo), MEMF_PUBLIC|MEMF_CLEAR)))
  209.     {
  210.     debug("RasInfo structure allocation failed");
  211.     _abort();
  212.     }
  213.  
  214.     debug("Allocated RasInfo OK");
  215.  
  216.     if (!(bmap2=(struct BitMap *)AllocMem(sizeof(struct BitMap),MEMF_PUBLIC|MEMF_CLEAR)))
  217.     {
  218.     debug("Bitmap structure allocation failed");
  219.     _abort();
  220.     }
  221.  
  222.     debug("Allocated BitMap OK");
  223.  
  224.     InitBitMap(bmap2, 2, wbscreen->Width, wbscreen->Height);
  225.  
  226.     debug("Initialized BitMap OK");
  227.  
  228.     /* we'll use 2 planes. */
  229.  
  230.     /* the (UWORD *) for AllocRaster is JimM's. I left it there and inserted the other to shut the compiler up. */
  231.  
  232.     if (! ( ((UWORD *)(bmap2->Planes[0])=(UWORD *)AllocRaster(wbscreen->Width, wbscreen->Height)) && ((UWORD *)(bmap2->Planes[1])=(UWORD *)AllocRaster(wbscreen->Width, wbscreen->Height))))
  233.     {
  234.     puts("AllocRaster failed while getting bitplanes");
  235.     _abort();
  236.     }
  237.  
  238.     debug("AllocRaster went OK");
  239.  
  240.     /* get a rastport, and set it up for rendering into bmap2 */
  241.     if (!(rport2 = (struct RastPort *)
  242.     AllocMem(sizeof (struct RastPort), MEMF_PUBLIC)))
  243.     {
  244.     puts("alloc rastport failed");
  245.     _abort();
  246.     }
  247.  
  248.     debug("Rastport structure allocated OK");
  249.  
  250.     InitRastPort(rport2);
  251.  
  252.     debug("Initialized rport structure OK");
  253.  
  254.     rport2->BitMap = bmap2;
  255.     SetRast(rport2, 0);
  256.  
  257.     /* manhandle viewport: install second playfield and change modes */
  258.     Forbid();
  259.  
  260.     /* install my bitmap in my rasinfo */
  261.     rinfo2->BitMap = bmap2;
  262.  
  263.     /* install rinfo for viewport's second playfield */
  264.     wbscreen->ViewPort.RasInfo->Next = rinfo2;
  265.  
  266.     /* convert viewport */
  267.     wbscreen->ViewPort.Modes |= DUALPF;
  268.  
  269.     it_is_done = TRUE;
  270.  
  271.     Permit();
  272.  
  273.     debug("Installed playfield, modes changed OK");
  274.  
  275.     /* put viewport changed into effect */
  276.     MakeScreen(wbscreen);
  277.     RethinkDisplay();
  278.  
  279.     vp = &wbscreen->ViewPort;    /* need these for colour operations */
  280.     map = vp->ColorMap;
  281.  
  282.     debug("Second playfield is now enabled.");
  283.  
  284. /*
  285.  *  Now I load in the picture to the already-created rastport. The picture
  286.  *  load routine ought to deal with any size or depth picture. If the
  287.  *  picture has more than 4 colours the extra bitplanes are ignored.
  288.  *
  289.  *  John Russell    12/31/87
  290.  *
  291.  */
  292.  
  293.     if (! (fp=fopen(picname,"r")))
  294.     {
  295.     printf("Unable to open picture %s.\n",picname);
  296.     _abort();
  297.     }
  298.  
  299.     debug("Opened picture file OK");
  300.  
  301.     if (!good_pict(fp))
  302.     {
  303.     puts("This is not an IFF picture I can recognize.");
  304.     _abort();
  305.     }
  306.  
  307.     debug("Picture is valid IFF");
  308.  
  309. /*    ,
  310.  *  Tres bummer! I can hack together an IFF reader that I feel comfortable
  311.  *  with faster than I can adapt any of the official code examples.
  312.  *
  313.  *  If I have anything to do with it, that won't be the situation much
  314.  *  longer. Look for the IFF equivalents to OpenWindow and CloseWindow
  315.  *  (ie one highly-structured call does all the work) coming soon.
  316.  *
  317.  *  The only IFF code I plagiarized was courtesy of Leo Schwab (much of the
  318.  *  header stuff and the load-bitmap outline). Please let me know of any
  319.  *  picture types you find cause problems for this program so I can correct
  320.  *  the situation.
  321.  *
  322.  */
  323.  
  324. /*
  325.  *  We have to get the chunks in a certain order; this is:
  326.  *
  327.  *  - FORM
  328.  *    - ILBM (not really a chunk, although it should be for consistency)
  329.  *        - CAMG and CMAP can go anywhere in this section
  330.  *        - BMHD
  331.  *        - BODY
  332.  *
  333.  */
  334.  
  335.     while (chunk_type = get_chunk(fp))
  336.     {
  337.     switch(chunk_type)
  338.     {
  339.         case CAMG:
  340.         /* this is not actually used, but might be by a future version */
  341.         debug("Read a CAMG chunk");
  342.         fread(&viewmodes,(int)chunk.chunksize,1,fp);
  343.         break;
  344.  
  345.         case BMHD:
  346.         debug("Read a BMHD chunk");
  347.         fread(&bmhd,(int)chunk.chunksize,1,fp);
  348.         got_bmhd = TRUE;
  349.         break;
  350.  
  351. /* have to provide some way to override these colours if user chooses */
  352.  
  353.         case CMAP:
  354.         {
  355.         register UBYTE *ctable;
  356.         register UWORD *cmap;
  357.         register long i,n;
  358.  
  359.         debug("Read a CMAP chunk");
  360.  
  361.         if (!(ctable = AllocMem (chunk.chunksize, NULL)))
  362.         {
  363.             debug("Colourtable alloc failed");
  364.             _abort();
  365.         }
  366.  
  367.         fread (ctable, (int) chunk.chunksize, 1, fp);
  368.  
  369.         if (!(cmap = AllocMem(chunk.chunksize * 2 / 3, NULL)))
  370.         {
  371.             debug("Colourmap alloc failed");
  372.             _abort();
  373.         }
  374.  
  375. /* NB: IFF stores more colour info, so we must get only 4 bits for each of RGB */
  376. /* Here is how you could load them in from a colormap. */
  377. /*           for (i = n = 0; i < (1 << actual_planes); i++, n+=3) */
  378. /*               cmap[i] = ((ctable[n] >> 4) << 8) + ((ctable[n+1] >> 4) << 4) + (ctable[n+2] >> 4); */
  379. /*           LoadRGB4 (viewport, cmap, (long) (1 << actual_planes)); */
  380.  
  381. /* However I only want a few, and in an already-setup viewport. */
  382.  
  383.         for (i = n = 0; i < (1 << actual_planes); i++, n+=3)
  384.             SetRGB4(vp, i+8, (long)(ctable[n] >> 4), (long)(ctable[n+1] >> 4), (long)(ctable[n+2] >> 4));
  385.  
  386.         FreeMem (cmap, chunk.chunksize * 2 / 3);
  387.         FreeMem (ctable, chunk.chunksize);
  388.  
  389.         }
  390.         break;
  391.  
  392.         case BODY:
  393.         if (got_bmhd)
  394.         {
  395.             /* this is the big "read picture into memory" part */
  396.             debug("Reading body chunk");
  397.             if (!get_body(fp,&bmhd,rport2->BitMap))
  398.             {
  399.             puts("Error while reading bitmap");
  400.             _abort();
  401.             }
  402.             got_body = TRUE;
  403.         }
  404.         else
  405.         {
  406.             puts("Body chunk is out of order!");
  407.             _abort();
  408.         }
  409.         break;
  410.  
  411.         default:
  412.         debug("Read unknown chunk type");
  413.         fseek(fp,chunk.chunksize,1);
  414.         break;
  415.     }
  416.     }
  417.     debug("Finished with all chunks");
  418.  
  419.     if (got_body == FALSE)
  420.     {
  421.     puts("Hey, no bitmap image present!");
  422.     _abort();
  423.     }
  424.  
  425.     /* now adjust colours if need be */
  426.  
  427.     if (background_opaque)
  428.     {
  429.     old_wbcolour = (ULONG)GetRGB4(map,0);
  430.  
  431.     if (set_pen0)
  432.     {
  433.         SetRGB4(vp, 0, (pen0 & 0xf00) >> 8, (pen0 & 0x0f0) >> 4, (pen0 & 0x00f));
  434.     }
  435.     else
  436.     {
  437.         background_colour = (ULONG)GetRGB4(map, 8);
  438.         SetRGB4(vp, 0, (background_colour & 0xf00) >> 8, (background_colour & 0x0f0) >> 4, (background_colour & 0x00f));
  439.     }
  440.     }
  441.  
  442.     if (set_pen1)
  443.     {
  444.     SetRGB4(vp, 9, (pen1 & 0xf00) >> 8, (pen1 & 0x0f0) >> 4, (pen1 & 0x00f));
  445.     }
  446.  
  447.     if (wbscreen->Width >= (bmhd.w << 1))
  448.     {
  449.     debug("Doubling picture horizontally");
  450.     for (count = wbscreen->Width; count; count -= 2)
  451.     {
  452.         ClipBlit(rport2,count/2,0,rport2,count-1,0,1,wbscreen->Height,0xc0);
  453.         ClipBlit(rport2,count/2,0,rport2,count-2,0,1,wbscreen->Height,0xc0);
  454.     }
  455.     }
  456.  
  457.     if (wbscreen->Height >= (bmhd.h << 1))
  458.     {
  459.     debug("Doubling picture vertically");
  460.     for (count = wbscreen->Height; count; count -= 2)
  461.     {
  462.         ClipBlit(rport2,0,count/2,rport2,0,count-1,wbscreen->Width,1,0xc0);
  463.         ClipBlit(rport2,0,count/2,rport2,0,count-2,wbscreen->Width,1,0xc0);
  464.     }
  465.     }
  466.  
  467.     if (bmhd.nplanes == 1)    /* don't need second plane for monochrome image */
  468.     {
  469.     Forbid();
  470.     if (ptr = bmap2->Planes[1])
  471.     {
  472.         bmap2->Planes[1] = NULL;
  473.         bmap2->Depth = 1;
  474.         FreeRaster(ptr, wbscreen->Width, wbscreen->Height);
  475.     }
  476.     Permit();
  477.  
  478.     /* put viewport changed into effect */
  479.     MakeScreen(wbscreen);
  480.     RethinkDisplay();
  481.     }
  482.  
  483.     FOREVER
  484.     {
  485.     if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL)
  486.     {
  487.         Wait( 1 << window->UserPort->mp_SigBit);
  488.         continue;
  489.     }
  490.  
  491.     class = msg->Class;
  492.     ReplyMsg(msg);
  493.  
  494.     switch (class)
  495.     {
  496.         case CLOSEWINDOW:
  497.         debug("event CLOSEWINDOW");
  498.         _abort();
  499.         break;
  500.         default:
  501.         debug("unknown event class");
  502.         break;
  503.     }
  504.     }
  505.  
  506. QUIT:
  507.  
  508.     debug("Arrived at QUIT routine");
  509.  
  510.     _abort();
  511. }
  512.  
  513. _abort()    /* so CTRL-c will be handled cleanly; unfortunately I have to declare a lot of variables globally to make it work */
  514. {
  515.     /* clean up dual-playfield trick    */
  516.  
  517.     if (it_is_done)
  518.     {
  519.     debug("Deleting second playfield");
  520.  
  521.     Forbid();
  522.     wbscreen->ViewPort.RasInfo->Next = NULL;
  523.     wbscreen->ViewPort.Modes &= ~DUALPF;
  524.     Permit();
  525.     MakeScreen(wbscreen);
  526.     RethinkDisplay();
  527.     }
  528.  
  529.     if (background_opaque)
  530.     {
  531.     SetRGB4(vp, 0, (old_wbcolour & 0xf00) >> 8, (old_wbcolour & 0x0f0) >> 4, (old_wbcolour & 0x00f));
  532.     }
  533.  
  534.     if (rport2) FreeMem(rport2, sizeof (struct RastPort));
  535.  
  536.     if (bmap2)
  537.     {
  538.     if (bmap2->Planes[0])
  539.     {
  540.         FreeRaster(bmap2->Planes[0], wbscreen->Width, wbscreen->Height);
  541.     }
  542.  
  543.     if (bmap2->Planes[1])
  544.     {
  545.         FreeRaster(bmap2->Planes[1], wbscreen->Width, wbscreen->Height);
  546.     }
  547.  
  548.     FreeMem(bmap2, sizeof (struct BitMap));
  549.     }
  550.  
  551.     if (rinfo2) FreeMem(rinfo2, sizeof (struct RasInfo));
  552.     if (fp) fclose(fp);
  553.     if (window) CloseWindow(window);
  554.     if (GfxBase) CloseLibrary(GfxBase);
  555.     if (IntuitionBase) CloseLibrary(IntuitionBase);
  556.  
  557.     exit (exitval);
  558. }
  559.  
  560. parse_args(ac,av)
  561. int ac;
  562. char **av;
  563. {
  564.     char option;
  565.  
  566.     debug("Parsing arguments");
  567.  
  568.     while((option = getopt(ac, av, optstring)) != EOF)
  569.     {
  570.     debug("Got argument");
  571.  
  572.     switch(toupper(option))
  573.     {
  574.         case 'B':
  575.         debug("Background will be opaque");
  576.         background_opaque = TRUE;
  577.         break;
  578.  
  579.         case '0':
  580.         debug("Set background colour");
  581.         set_pen0 = TRUE;
  582.         background_opaque = TRUE;
  583.         sscanf(optarg,"%x",&pen0);
  584.         break;
  585.  
  586.         case '1':
  587.         debug("Set pen #1 colour");
  588.         set_pen1 = TRUE;
  589.         sscanf(optarg,"%x",&pen1);
  590.         break;
  591.  
  592.         default:
  593.         debug("Unknown argument");
  594.         break;
  595.     }
  596.     }
  597. }
  598.  
  599.