home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 274.lha / SimGen_Src / cbmreadpict.c < prev    next >
C/C++ Source or Header  |  1989-07-26  |  14KB  |  450 lines

  1. /** myReadPict.c ************************************************************
  2.  *
  3.  * Read an ILBM raster image file.               23-Jan-86.
  4.  *
  5.  * Modified version of ReadPict.c 
  6.  *   by Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
  7.  *   This software is in the public domain.
  8.  *
  9.  * Modified by C. Scheppner  11/86
  10.  *   Handles CAMG chunks for HAM, etc.
  11.  *   Calls user defined routine getBitMap(ilbmFramePtr) when it
  12.  *      reaches the BODY.
  13.  *   getBitMap() can open a screen of the correct size using
  14.  *      information this rtn places in the ilbmFrame, and returns
  15.  *      a pointer to a BitMap structure.  The BitMap structure
  16.  *      tells myReadPicture where it should load the bit planes.
  17.  *
  18.  * Modified by C. Scheppner  12/86
  19.  *   Loads in CCRT or CRNG chunks (converts CCRT to CRNG)
  20.  *
  21.  *
  22.  * Modified by Gregg Tavares 1/89
  23.  *   Does Things I want it to do.
  24.  *     1) Loads Infinite CyclesRanges
  25.  *     2) Options to load GRAB chuncks
  26.  *     3) Options to load parts of a pic
  27.  *     4) Options to alloc mem for pic or use caller supplied memory
  28.  *     5) Will load into a bitmap or a rastport
  29.  ****************************************************************************/
  30.  
  31. #define LOCAL   static
  32.  
  33. #include <exec/memory.h>
  34. #include <intuition/intuition.h>
  35. #include <libraries/dos.h>
  36. #include <libraries/dosextens.h>
  37. #include <iff/ilbm.h>
  38. #include <iff/readpict.h>    /* cs */
  39. #include "picture.h"
  40.  
  41. /* Define size of a temporary buffer used in unscrambling the ILBM rows.*/
  42. #define bufSz 512
  43.  
  44. /*------------ ILBM reader -----------------------------------------------*/
  45. /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
  46.  * We allocate one of these on the stack for every LIST or FORM encountered
  47.  * in the file and use it to hold BMHD & CMAP properties. We also allocate
  48.  * an initial one for the whole file.
  49.  * We allocate a new GroupContext (and initialize it by OpenRIFF or
  50.  * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
  51.  * just a context for reading (nested) chunks.
  52.  *
  53.  * If we were to scan the entire example file outlined below:
  54.  *    reading          proc(s)                new               new
  55.  *
  56.  * --whole file--   myReadPicture+ReadIFF GroupContext        ILBMFrame
  57.  * CAT              ReadICat                GroupContext
  58.  *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
  59.  *     PROP ILBM    GetPrILBM                   GroupContext
  60.  *       CMAP       GetCMAP
  61.  *       BMHD       GetBMHD
  62.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  63.  *       BODY       GetBODY
  64.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  65.  *       BODY       GetBODY
  66.  *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
  67.  */
  68.  
  69. /* NOTE: For a small version of this program, set Fancy to 0.
  70.  * That'll compile a program that reads a single FORM ILBM in a file, which
  71.  * is what DeluxePaint produces. It'll skip all LISTs and PROPs in the input
  72.  * file. It will, however, look inside a CAT for a FORM ILBM.
  73.  * That's suitable for 90% of the uses.
  74.  *
  75.  * For a fancier version that handles LISTs and PROPs, set Fancy to 1.
  76.  * That'll compile a program that dives into a LIST, if present, to read
  77.  * the first FORM ILBM. E.g. a DeluxePrint library of images is a LIST of
  78.  * FORMs ILBM.
  79.  *
  80.  * For an even fancier version, set Fancy to 2. That'll compile a program
  81.  * that dives into non-ILBM FORMs, if present, looking for a nested FORM ILBM.
  82.  * E.g. a DeluxeVideo C.S. animated object file is a FORM ANBM containing a
  83.  * FORM ILBM for each image frame. */
  84. #define Fancy  2
  85.  
  86. /* Global access to client-provided pointers.*/
  87. LOCAL ILBMFrame *giFrame = NULL;   /* "client frame".*/
  88.  
  89.  
  90. CycleRange **LastCycleRange (cr)
  91.     CycleRange **cr;
  92. {
  93.     while (*cr)
  94.         cr = &(CycleRange *)(*cr)->NextRange;
  95.  
  96.     return cr;
  97. }
  98.  
  99. IFFP handleCAMG(context,frame)
  100.     GroupContext *context;
  101.     ILBMFrame    *frame;
  102. {
  103.     IFFP        iffp = IFF_OKAY;
  104.     CamgChunk    camgTemp;
  105.  
  106.     PicValidModes(frame->pic) = TRUE;
  107.     iffp = GetCAMG(context, &camgTemp);
  108.     PicViewModes(frame->pic) = camgTemp.ViewModes;
  109.     return(iffp);
  110. }
  111.  
  112. IFFP handleCRNG(context,frame)
  113.     GroupContext *context;
  114.     ILBMFrame    *frame;
  115. {
  116.     IFFP        iffp = IFF_OKAY;
  117.     CycleRange    **cr;
  118.     CrngChunk    crngTemp;
  119.  
  120.     if (frame->ni->Flags & NI_GETCYCLES) {
  121.         /* Point to last range */
  122.         cr = LastCycleRange (&PicCycleRanges(frame->pic));
  123.  
  124.         /* Allocate New Range */
  125.         if(!( *cr = (CycleRange *)(*frame->allocmem)(sizeof (CycleRange), MEMF_CLEAR))) {
  126.             return (CLIENT_ERROR);
  127.         }
  128.  
  129.         /* Get CRNG Chunk from File */
  130.         iffp = GetCRNG(context,&crngTemp);
  131.  
  132.         /* Copy relevant information */
  133.         (*cr)->rate   = crngTemp.rate;
  134.         (*cr)->active = crngTemp.active;
  135.         (*cr)->low    = crngTemp.low;
  136.         (*cr)->high   = crngTemp.high;
  137.  
  138.     } else {
  139.  
  140.         /* Get CRNG Chunk from File */
  141.         iffp = GetCRNG(context,&crngTemp);
  142.  
  143.     }
  144.     return(iffp);
  145. }
  146.  
  147.  
  148. IFFP handleCCRT(context,frame)
  149.     GroupContext *context;
  150.     ILBMFrame    *frame;
  151. {
  152.     CycleRange    **cr;
  153.     CcrtChunk    ccrtTemp;
  154.     IFFP        iffp = IFF_OKAY;
  155.  
  156.     if (frame->ni->Flags & NI_GETCYCLES) {
  157.         /* Point to last range */
  158.         cr = LastCycleRange (frame->pic);
  159.  
  160.         /* Allocate New Range */
  161.         if(!( *cr = (CycleRange *)(*frame->allocmem)(sizeof (CycleRange), MEMF_CLEAR))) {
  162.             return (CLIENT_ERROR);
  163.         }
  164.  
  165.         /* Get CCRT Chunk from file */
  166.         iffp = GetCCRT(context, &ccrtTemp);
  167.  
  168.         /* Copy Relevant information */
  169.         if(ccrtTemp.direction) {
  170.             ccrtTemp.direction = -ccrtTemp.direction;
  171.         }
  172.         (*cr)->active = ccrtTemp.direction & 0x03;
  173.         (*cr)->low    = ccrtTemp.start;
  174.         (*cr)->high   = ccrtTemp.end;
  175.  
  176.       /* Convert  CCRT secs/msecs to CRNG timimg
  177.        * 0x4000 = max CRNG rate  (cycle every 1 60th sec)
  178.        * This must be divided by # 60th's between cycles
  179.        * seconds to 60th's is easy
  180.        * msecs to 60th's requires division by 16667
  181.        * this is int math so I add 8334 (half 16667) first for rounding
  182.        */
  183.         (*cr)->rate = 0x4000 /
  184.             ((ccrtTemp.seconds * 60)+((ccrtTemp.microseconds+8334)/16667));
  185.     } else {
  186.  
  187.         /* Get CCRT Chunk from file */
  188.         iffp = GetCCRT(context, &ccrtTemp);
  189.  
  190.     }
  191.  
  192.     return(iffp);
  193. }
  194.  
  195.  
  196. /** GetFoILBM() *************************************************************
  197.  *
  198.  * Called via myReadPictureto handle every FORM encountered in an IFF file.
  199.  * Reads FORMs ILBM and skips all others.
  200.  * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
  201.  * finds no BODY or if it has no BMHD to decode the BODY.
  202.  *
  203.  * Once we find a BODY chunk, we'll call user rtn getBitMap() to
  204.  *    allocate the bitmap and planes (or screen) and then read
  205.  *    the BODY into the planes.
  206.  *
  207.  ****************************************************************************/
  208. LOCAL BYTE bodyBuffer[bufSz];
  209. IFFP GetFoILBM(parent)
  210.     GroupContext *parent;
  211. {
  212.     /*compilerBug register*/ IFFP iffp;
  213.     GroupContext    formContext;
  214.     ILBMFrame    ilbmFrame;    /* only used for non-clientFrame fields.*/
  215.     UBYTE        *buffer;
  216.     ULONG        bufsize;
  217.     struct BitMap    srcbm;
  218.  
  219.     /* Handle a non-ILBM FORM. */
  220.     if (parent->subtype != ID_ILBM) {
  221. #if Fancy >= 2
  222.         /* Open a non-ILBM FORM and recursively scan it for ILBMs.*/
  223.         iffp = OpenRGroup(parent, &formContext);
  224.         CheckIFFP();
  225.         do {
  226.             iffp = GetF1ChunkHdr(&formContext);
  227.         } while (iffp >= IFF_OKAY);
  228.         if (iffp == END_MARK) {
  229.             iffp = IFF_OKAY;   /* then continue scanning the file */
  230.         }
  231.         CloseRGroup(&formContext);
  232.         return(iffp);
  233. #else
  234.         return(IFF_OKAY); /* Just skip this FORM and keep scanning the file.*/
  235. #endif
  236.     }
  237.  
  238.     ilbmFrame = *(ILBMFrame *)parent->clientFrame;
  239.     iffp = OpenRGroup(parent, &formContext);
  240.     CheckIFFP();
  241.  
  242.     do switch (iffp = GetFChunkHdr(&formContext)) {
  243.     case ID_BMHD: {
  244.         ilbmFrame.foundBMHD = TRUE;
  245.         iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
  246.         break; }
  247.     case ID_CAMG: {       /* cs */
  248.         iffp = handleCAMG(&formContext, &ilbmFrame);
  249.         break; }
  250.     case ID_CRNG: {       /* cs */
  251.         iffp = handleCRNG(&formContext, &ilbmFrame);
  252.         break; }
  253.     case ID_CCRT: {       /* cs */
  254.         iffp = handleCCRT(&formContext, &ilbmFrame);
  255.         break; }
  256.     case ID_CMAP: {
  257.         PicColors(ilbmFrame.pic) = maxColorReg; /* room for this many */
  258.         iffp = GetCMAP(&formContext,
  259.                    (WORD *)PicColorMap(ilbmFrame.pic),
  260.                 &PicColors(ilbmFrame.pic));
  261.         break; }
  262.     case ID_BODY: {       /* cs */
  263.         if (!ilbmFrame.foundBMHD) {
  264.             iffp = BAD_FORM;   /* No BMHD chunk! */
  265.         } else {
  266.             bufsize = RowBytes (ilbmFrame.bmHdr.w) * 3;
  267.             if (!(buffer = (ilbmFrame.allocmem)(bufsize, NULL))) {
  268.                 iffp = CLIENT_ERROR;
  269.             } else {
  270.                 int i;
  271.                 BOOL error = FALSE;
  272.  
  273.                 ClearMem (&srcbm, sizeof (srcbm));
  274.                 InitBitMap (&srcbm,
  275.                     ilbmFrame.bmHdr.nPlanes,
  276.                     ilbmFrame.bmHdr.w,
  277.                     1);
  278.  
  279.                 for (i=0; i<ilbmFrame.bmHdr.nPlanes && !error; i++) {
  280.                     if (!(srcbm.Planes[i] = (*ilbmFrame.allocmem)(RASSIZE (ilbmFrame.bmHdr.w, 1), MEMF_CHIP))) {
  281.                         error = TRUE;
  282.                         iffp  = CLIENT_ERROR;
  283.                     }
  284.                 }
  285.  
  286.                 if (!error) {
  287.                     iffp = GetBODY( &formContext,
  288.                             &ilbmFrame,
  289.                             NULL,
  290.                             buffer,
  291.                             bufsize,
  292.                             &srcbm);
  293.                 }
  294.  
  295.                 for (i=0; i<ilbmFrame.bmHdr.nPlanes; i++) {
  296.                     if (srcbm.Planes[i]) {
  297.                         FreeMem (srcbm.Planes[i],
  298.                             RASSIZE (ilbmFrame.bmHdr.w, 1));
  299.                     }
  300.                 }
  301.  
  302.                 FreeMem (buffer, bufsize);
  303.                 if (iffp == IFF_OKAY) {
  304.                     iffp = IFF_DONE;   /* Eureka */
  305.                 }
  306.                 *giFrame = ilbmFrame; /* copy fields to client frame */
  307.             }
  308.         }
  309.         break; }
  310.     case END_MARK: {
  311.         iffp = BAD_FORM;
  312.         break; }
  313.     } while (iffp >= IFF_OKAY);
  314.  
  315.     /* loop if valid ID of ignored chunk or a
  316.      * subroutine returned IFF_OKAY (no errors).*/
  317.  
  318.     if (iffp != IFF_DONE)  return(iffp);
  319.  
  320.     CloseRGroup(&formContext);
  321.     return(iffp);
  322. }
  323.  
  324. /** Notes on extending GetFoILBM ********************************************
  325.  *
  326.  * To read more kinds of chunks, just add clauses to the switch statement.
  327.  * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
  328.  * the switch statement in GetPrILBM, too.
  329.  *
  330.  * To read a FORM type that contains a variable number of data chunks--e.g.
  331.  * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
  332.  * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
  333.  * case do whatever cleanup you need.
  334.  *
  335.  ****************************************************************************/
  336.  
  337.  
  338. /** GetPrILBM() *************************************************************
  339.  *
  340.  * Called via myReadPicture to handle every PROP encountered in an IFF file.
  341.  * Reads PROPs ILBM and skips all others.
  342.  *
  343.  ****************************************************************************/
  344. #if Fancy
  345. IFFP GetPrILBM(parent)
  346.     GroupContext *parent;
  347. {
  348.     /*compilerBug register*/ IFFP iffp;
  349.     GroupContext    propContext;
  350.     ILBMFrame    *ilbmFrame = (ILBMFrame *)parent->clientFrame;
  351.  
  352.     if (parent->subtype != ID_ILBM)
  353.         return(IFF_OKAY);   /* just continue scaning the file */
  354.  
  355.     iffp = OpenRGroup(parent, &propContext);
  356.         CheckIFFP();
  357.  
  358.     do switch (iffp = GetPChunkHdr(&propContext)) {
  359.     case ID_BMHD: {
  360.         ilbmFrame->foundBMHD = TRUE;
  361.         iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
  362.         break; }
  363.     case ID_CAMG: {       /* cs */
  364.         iffp = handleCAMG(&propContext, ilbmFrame);
  365.         break; }
  366.     case ID_CRNG: {       /* cs */
  367.         iffp = handleCRNG(&propContext, ilbmFrame);
  368.         break; }
  369.     case ID_CCRT: {       /* cs */
  370.         iffp = handleCCRT(&propContext, ilbmFrame);
  371.         break; }
  372.     case ID_CMAP: {
  373.         PicColors(ilbmFrame->pic) = maxColorReg; /* room for this many */
  374.         iffp = GetCMAP(&propContext,
  375.                 (WORD *)PicColorMap(ilbmFrame->pic),
  376.                 &PicColors(ilbmFrame->pic));
  377.         break; }
  378.     } while (iffp >= IFF_OKAY);
  379.     /* loop if valid ID of ignored chunk or a
  380.     * subroutine returned IFF_OKAY (no errors).*/
  381.  
  382.     CloseRGroup(&propContext);
  383.     return(iffp == END_MARK ? IFF_OKAY : iffp);
  384. }
  385. #endif
  386.  
  387. /** GetLiILBM() *************************************************************
  388.  *
  389.  * Called via myReadPicture to handle every LIST encountered in an IFF file.
  390.  *
  391.  ****************************************************************************/
  392. #if Fancy
  393. IFFP GetLiILBM(parent)
  394.     GroupContext *parent;
  395. {
  396.     ILBMFrame newFrame;   /* allocate a new Frame */
  397.  
  398.     newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
  399.  
  400.     return( ReadIList(parent, (ClientFrame *)&newFrame) );
  401. }
  402. #endif
  403.  
  404. /** myReadPicture() ********************************************************/
  405. IFFP myReadPicture(file,iFrame)
  406.     LONG file;
  407.     ILBMFrame *iFrame;   /* Top level "client frame".*/
  408. {
  409.     IFFP iffp = IFF_OKAY;
  410.  
  411. #if Fancy
  412.     iFrame->clientFrame.getList = GetLiILBM;
  413.     iFrame->clientFrame.getProp = GetPrILBM;
  414. #else
  415.     iFrame->clientFrame.getList = SkipGroup;
  416.     iFrame->clientFrame.getProp = SkipGroup;
  417. #endif
  418.     
  419.     iFrame->clientFrame.getForm = GetFoILBM;
  420.     iFrame->clientFrame.getCat  = ReadICat ;
  421.  
  422.    /* Initialize the top-level client frame's property settings to the
  423.     * program-wide defaults. This example just records that we haven't read
  424.     * any BMHD property or CMAP color registers yet. For the color map, that
  425.     * means the default is to leave the machine's color registers alone.
  426.     * If you want to read a property like GRAB, init it here to (0, 0). */
  427.  
  428.     iFrame->foundBMHD          = FALSE;
  429.     PicColors(iFrame->pic)     = 0;
  430.     PicValidModes(iFrame->pic) = FALSE;    /* cs */
  431.     giFrame = iFrame;
  432.  
  433.   /* Store a pointer to the client's frame in a global variable so that
  434.    * GetFoILBM can update client's frame when done.  Why do we have so
  435.    * many frames & frame pointers floating around causing confusion?
  436.    * Because IFF supports PROPs which apply to all FORMs in a LIST,
  437.    * unless a given FORM overrides some property.  
  438.    * When you write code to read several FORMs,
  439.    * it is ssential to maintain a frame at each level of the syntax
  440.    * so that the properties for the LIST don't get overwritten by any
  441.    * properties specified by individual FORMs.
  442.    * We decided it was best to put that complexity into this one-FORM example,
  443.    * so that those who need it later will have a useful starting place.
  444.    */
  445.  
  446.     iffp = ReadIFF(file, (ClientFrame *)iFrame);
  447.     return(iffp);
  448. }
  449.  
  450.