home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 22 / AACD 22.iso / AACD / Graphics / FlashMandel / Sources / Modules / IffModules / ilbmr.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-20  |  16.2 KB  |  527 lines

  1. /* ilbmr.c --- ILBM loading routines for use with iffparse */
  2.  
  3. /*----------------------------------------------------------------------*
  4.  * ILBMR.C  Support routines for reading ILBM files.
  5.  * (IFF is Interchange Format File.)
  6.  *
  7.  * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
  8.  * This software is in the public domain.
  9.  * Modified for iffparse.library 05/90
  10.  * This version for the Commodore-Amiga computer.
  11.  *
  12.  * 37.9 04/92
  13.  * 39.1 07/92 - add setcolors() and support for V39 color loading
  14.  * 39.2 09/92 - only check AllShifted for colors that are used.
  15.  * 39.3 09/92 - obey CMAPOK advisories
  16.  * 39.4 09/92 - fix CMAPOK code (39.3 bug was ignoring colors if bit set)
  17.  * 39.5 11/92 - add GetBitMapAttr/destWidthBytes check
  18.  * 39.7  1/93 - clear modeid before calculating one for bad/missing camg
  19.  *----------------------------------------------------------------------*/
  20.  
  21. #define INTUI_V36_NAMES_ONLY
  22.  
  23. #include "iffp/ilbm.h"
  24. #include "iffp/packer.h"
  25. #include "iffp/ilbmapp.h"
  26.  
  27. #define movmem CopyMem
  28.  
  29. #define MaxSrcPlanes (25)
  30.  
  31. extern struct Library *GfxBase;
  32.  
  33. /*---------- loadbody ---------------------------------------------------*/
  34.  
  35. LONG loadbody(struct IFFHandle *iff,struct BitMap *bitmap,BitMapHeader *bmhd)
  36.     {
  37.     BYTE *buffer;
  38.     ULONG bufsize;
  39.     LONG error = 1;
  40.  
  41.     D(bug("In loadbody\n"));
  42.  
  43.     if(!(currentchunkis(iff,ID_ILBM,ID_BODY)))
  44.         {
  45.         message(SI(MSG_ILBM_NOBODY));   /* Maybe it's a palette */
  46.         return(IFF_OKAY);
  47.         }
  48.  
  49.     if((bitmap)&&(bmhd))
  50.         {
  51.         D(bug("Have bitmap and bmhd\n"));
  52.  
  53.         bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
  54.             if(!(buffer = AllocMem(bufsize,0L)))
  55.         {
  56.         D(bug("Buffer alloc of %ld failed\n",bufsize));
  57.         return(IFFERR_NOMEM);
  58.         }
  59.         error = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
  60.         D(bug("Returned from loadbody2, error = %ld\n",error));
  61.         }
  62.     FreeMem(buffer,bufsize);
  63.     return(error);
  64.     }
  65.  
  66.  
  67. /* like the old GetBODY */
  68. LONG loadbody2(struct IFFHandle *iff, struct BitMap *bitmap, BYTE *mask, BitMapHeader *bmhd, BYTE *buffer, ULONG bufsize)
  69.    {
  70.    UBYTE srcPlaneCnt = bmhd->nPlanes;   /* Haven't counted for mask plane yet*/
  71.    WORD srcRowBytes = RowBytes(bmhd->w);
  72.    WORD destRowBytes = bitmap->BytesPerRow;   /* used as a modulo only */
  73.    LONG bufRowBytes = MaxPackedSize(srcRowBytes);
  74.    int nRows = bmhd->h;
  75.    WORD destWidthBytes;         /* used for width check */
  76.    WORD compression = bmhd->compression;
  77.    register int iPlane, iRow, nEmpty;
  78.    register WORD nFilled;
  79.    BYTE *buf, *nullDest, *nullBuf, **pDest;
  80.    BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
  81.    struct ContextNode *cn;
  82.  
  83.    D(bug("loadbody2: srcRowBytes = %ld\n",srcRowBytes));
  84.  
  85.    cn = CurrentChunk(iff);
  86.  
  87.    if (compression > cmpByteRun1)
  88.       return(CLIENT_ERROR);
  89.  
  90.    /* If >=V39, this may be an interleaved bitmap with a BytesPerRow
  91.     * which is truly just a modulo and actually includes ALL planes.
  92.     * So instead, for bounds checking, we use the pixel width of
  93.     * the BitMap rounded up to nearest WORD, since saved ILBMs
  94.     * are always saved as their width rounded up to nearest WORD.
  95.     */
  96.    if(GfxBase->lib_Version >= 39)
  97.     {
  98.     destWidthBytes = RowBytes(GetBitMapAttr(bitmap,BMA_WIDTH));
  99.     }
  100.    else destWidthBytes = destRowBytes;
  101.  
  102.    D(bug("loadbody2: compression=%ld srcBytes=%ld bitmapBytes=%ld\n",
  103.         compression, srcRowBytes, bitmap->BytesPerRow));
  104.    D(bug("loadbody2: bufsize=%ld bufRowBytes=%ld, srcPlaneCnt=%ld\n",
  105.             bufsize, bufRowBytes, srcPlaneCnt));
  106.  
  107.    /* Complain if client asked for a conversion GetBODY doesn't handle.*/
  108.    if ( srcRowBytes  >  destWidthBytes  ||
  109.          bufsize < bufRowBytes * 2  ||
  110.          srcPlaneCnt > MaxSrcPlanes )
  111.       return(CLIENT_ERROR);
  112.  
  113.    D(bug("loadbody2: past conversion checks\n"));
  114.  
  115.    if (nRows > bitmap->Rows)   nRows = bitmap->Rows;
  116.  
  117.    D(bug("loadbody2: srcRowBytes=%ld, srcRows=%ld, srcDepth=%ld, destDepth=%ld\n",
  118.         srcRowBytes, nRows, bmhd->nPlanes, bitmap->Depth));
  119.    
  120.    /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
  121.    for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
  122.       planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
  123.    for ( ;  iPlane < MaxSrcPlanes;  iPlane++)
  124.       planes[iPlane] = NULL;
  125.  
  126.    /* Copy any mask plane ptr into corresponding "planes" slot.*/
  127.    if (bmhd->masking == mskHasMask)
  128.     {
  129.         if (mask != NULL)
  130.              planes[srcPlaneCnt] = mask;  /* If there are more srcPlanes than
  131.                * dstPlanes, there will be NULL plane-pointers before this.*/
  132.         else
  133.              planes[srcPlaneCnt] = NULL;  /* In case more dstPlanes than src.*/
  134.         srcPlaneCnt += 1;  /* Include mask plane in count.*/
  135.         }
  136.  
  137.    /* Setup a sink for dummy destination of rows from unwanted planes.*/
  138.    nullDest = buffer;
  139.    buffer  += srcRowBytes;
  140.    bufsize -= srcRowBytes;
  141.  
  142.    /* Read the BODY contents into client's bitmap.
  143.     * De-interleave planes and decompress rows.
  144.     * MODIFIES: Last iteration modifies bufsize.*/
  145.  
  146.    buf = buffer + bufsize;  /* Buffer is currently empty.*/
  147.    for (iRow = nRows; iRow > 0; iRow--)
  148.     {
  149.         for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
  150.         {
  151.         pDest = &planes[iPlane];
  152.  
  153.             /* Establish a sink for any unwanted plane.*/
  154.             if (*pDest == NULL)
  155.         {
  156.             nullBuf = nullDest;
  157.                 pDest   = &nullBuf;
  158.                 }
  159.  
  160.             /* Read in at least enough bytes to uncompress next row.*/
  161.             nEmpty  = buf - buffer;   /* size of empty part of buffer.*/
  162.             nFilled = bufsize - nEmpty;   /* this part has data.*/
  163.         if (nFilled < bufRowBytes)
  164.         {
  165.             /* Need to read more.*/
  166.  
  167.             /* Move the existing data to the front of the buffer.*/
  168.             /* Now covers range buffer[0]..buffer[nFilled-1].*/
  169.                 movmem(buf, buffer, nFilled);  /* Could be moving 0 bytes.*/
  170.  
  171.                 if(nEmpty > ChunkMoreBytes(cn))
  172.             {
  173.                     /* There aren't enough bytes left to fill the buffer.*/
  174.                     nEmpty = ChunkMoreBytes(cn);
  175.                     bufsize = nFilled + nEmpty;  /* heh-heh */
  176.                     }
  177.  
  178.             /* Append new data to the existing data.*/
  179.                 if(ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
  180.             return(CLIENT_ERROR);
  181.  
  182.                 buf     = buffer;
  183.             nFilled = bufsize;
  184.             nEmpty  = 0;
  185.             }
  186.  
  187.         /* Copy uncompressed row to destination plane.*/
  188.             if(compression == cmpNone)
  189.         {
  190.                 if(nFilled < srcRowBytes)  return(IFFERR_MANGLED);
  191.             movmem(buf, *pDest, srcRowBytes);
  192.             buf    += srcRowBytes;
  193.                 *pDest += destRowBytes;
  194.                 }
  195.         else
  196.         {
  197.             /* Decompress row to destination plane.*/
  198.                 if ( unpackrow(&buf, pDest, nFilled,  srcRowBytes) )
  199.                     /*  pSource, pDest, srcBytes, dstBytes  */
  200.                     return(IFFERR_MANGLED);
  201.             else *pDest += (destRowBytes - srcRowBytes);
  202.         }
  203.         }
  204.     }
  205.    return(IFF_OKAY);
  206.    }
  207.  
  208.  
  209. /* ----------- getcolors ------------- */
  210.  
  211. /* getcolors - allocates a ilbm->colortable for at least 32 registers
  212.  *      and loads CMAP colors into it, setting ilbm->ncolors to number
  213.  *      of colors actually loaded.
  214.  *
  215.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
  216.  *  allocate and build a 32-bit per gun colortable (ilbm->colortable32)
  217.  *  and ilbm->colorrecord for LoadRGB32().  
  218.  */
  219.  
  220. LONG getcolors(struct ILBMInfo *ilbm)
  221.     {
  222.     struct IFFHandle    *iff;
  223.     LONG error;
  224.  
  225.     if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);
  226.  
  227.     if(!(error = alloccolortable(ilbm)))
  228.        error = loadcmap(ilbm);
  229.     if(error) freecolors(ilbm);
  230.     D(bug("getcolors: error = %ld\n",error));
  231.     return(error);
  232.     }
  233.  
  234.  
  235. /* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
  236.  *  to the number of colors we have room for in the table.
  237.  *
  238.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will also
  239.  *  allocate and build a 32-bit per gun colortable (ilbm->colortable32)
  240.  *  and ilbm->colorrecord for LoadRGB32()
  241.  */ 
  242.  
  243. LONG alloccolortable(struct ILBMInfo *ilbm)
  244.     {
  245.     struct IFFHandle    *iff;
  246.     struct  StoredProperty  *sp;
  247.  
  248.     LONG    error = CLIENT_ERROR;
  249.     ULONG   ctabsize;
  250.     USHORT  ncolors;
  251.  
  252.     if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);
  253.  
  254.     if(sp = FindProp (iff, ID_ILBM, ID_CMAP))
  255.         {
  256.         /*
  257.          * Compute the size table we need
  258.          */
  259.         ncolors = sp->sp_Size / 3;      /* how many in CMAP */
  260.         ncolors = MAX(ncolors, 32);     /* alloc at least 32 */
  261.  
  262.         ctabsize = ncolors * sizeof(Color4);
  263.         if(ilbm->colortable = 
  264.            (Color4 *)AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
  265.             {
  266.             ilbm->ncolors = ncolors;
  267.             ilbm->ctabsize = ctabsize;
  268.             error = 0L;
  269.  
  270.             if((GfxBase->lib_Version >= 39)&&
  271.                 (!(ilbm->IFFPFlags & IFFPF_NOCOLOR32)))
  272.             {
  273.             ctabsize = (ncolors * sizeof(Color32))+(4 * sizeof(WORD));
  274.             if(ilbm->colorrecord = (WORD *) 
  275.                AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC))
  276.                 {
  277.                 ilbm->crecsize = ctabsize; 
  278.                 ilbm->colortable32 = (Color32 *)(&ilbm->colorrecord[2]);
  279.                 ilbm->colorrecord[0] = ncolors; /* For LoadRGB32 */
  280.                 ilbm->colorrecord[1] = 0;
  281.                 }
  282.             else error = IFFERR_NOMEM;
  283.             }
  284.             }
  285.         else error = IFFERR_NOMEM;
  286.         }
  287.     D(bug("alloccolortable for %ld colors: error = %ld\n",ncolors,error));
  288.  
  289.     if(error)   freecolors(ilbm);
  290.     return(error);
  291.     }
  292.  
  293.  
  294. void freecolors(struct ILBMInfo *ilbm)
  295.     {
  296.     if(ilbm->colortable)
  297.         {
  298.         FreeMem(ilbm->colortable, ilbm->ctabsize);
  299.         }
  300.     ilbm->colortable = NULL;
  301.     ilbm->ctabsize = 0;
  302.  
  303.     if(ilbm->colorrecord)
  304.         {
  305.         FreeMem(ilbm->colorrecord, ilbm->crecsize);
  306.         }
  307.     ilbm->colorrecord  = NULL;
  308.     ilbm->colortable32 = NULL;
  309.     ilbm->crecsize = 0;
  310.     }
  311.  
  312.  
  313.  
  314. /* loadcmap - note interface change for V39
  315.  *
  316.  * Passed ILBMInfo
  317.  *
  318.  * Sets ncolors (and colorrecord if using it) to the number actually read.
  319.  *
  320.  *  New for V39 and above: If bmhd->flags BMHDF_CMAPOK is set,
  321.  *  or if ILBMInfo->IFFPFlags IFFPF_CMAPOK is set, the 32-bit gun code
  322.  *  will assume the CMAP contains 8-bit significant guns (R,G,B)
  323.  *  and will not scale apparent 4-bit nibbles to 8 bits prior to
  324.  *  scaling to 32 bits.  In the absence of either of these flags,
  325.  *  if whole usable CMAP contains RGB values whose low nibbles are all 0,
  326.  *  this code will first scale the RGB values to 8 bits ($30 becomes $33, etc)
  327.  */ 
  328.  
  329. LONG loadcmap(struct ILBMInfo *ilbm)
  330.     {
  331.     struct StoredProperty   *sp;
  332.     LONG            k;
  333.     ULONG           ncolors, gun, ncheck;
  334.     UBYTE           *rgb, rb, gb, bb;
  335.     ULONG           nc, r, g, b;
  336.     struct IFFHandle    *iff;
  337.     BOOL AllShifted;
  338.  
  339.  
  340.     if(!(iff=ilbm->ParseInfo.iff))  return(CLIENT_ERROR);
  341.  
  342.     if(!(ilbm->colortable))
  343.     {
  344.     message(SI(MSG_ILBM_NOCOLORS));
  345.     return(1);
  346.     }
  347.  
  348.     if(!(sp = FindProp (iff, ID_ILBM, ID_CMAP)))    return(1);
  349.  
  350.  
  351.     rgb = sp->sp_Data;
  352.  
  353.     /* file has this many colors */
  354.     nc = sp->sp_Size / sizeofColorRegister;
  355.     ncolors = nc;
  356.  
  357.     /* if ILBMInfo can't hold that many, we'll load less */
  358.     if(ilbm->ncolors < ncolors) ncolors = ilbm->ncolors;
  359.     /* set to how many we are loading */
  360.     ilbm->ncolors = ncolors;
  361.  
  362.     /* how many colors to check for shifted nibbles (i.e. used colors) */
  363.     ncheck = 1 << ilbm->Bmhd.nPlanes;
  364.     if(ncheck > ncolors) ncheck = ncolors;
  365.  
  366.     if((GfxBase->lib_Version >= 39)
  367.         && (!(ilbm->IFFPFlags & IFFPF_NOCOLOR32))
  368.             &&(ilbm->colorrecord))
  369.     {
  370.     ilbm->colorrecord[0] = ncolors;
  371.  
  372.     /* Assign to 32-bit table, examine for all-shifted nibbles at same time */
  373.     AllShifted = TRUE;
  374.     k = 0;
  375.         while (ncheck--) 
  376.             {
  377.             ilbm->colortable32[k].r = rb = *rgb++;
  378.             ilbm->colortable32[k].g = gb = *rgb++;
  379.             ilbm->colortable32[k].b = bb = *rgb++;
  380.         if(((rb & 0x0F) || (gb & 0x0F) || (bb & 0x0F)))
  381.             AllShifted=FALSE;
  382.             k++;
  383.             }
  384.  
  385.     /* If no file/user indication that this is an 8-bit significant CMAP... */
  386.     if( (!(ilbm->IFFPFlags & IFFPF_CMAPOK)) &&
  387.         (!(ilbm->Bmhd.flags & BMHDF_CMAPOK)) )
  388.         {
  389.         /* If all nibbles appear shifted (4 bit), duplicate the nibbles */
  390.         if(AllShifted)
  391.             {
  392.             for(k = 0; k <nc; k++)
  393.             {
  394.             ilbm->colortable32[k].r |= (ilbm->colortable32[k].r >> 4);
  395.             ilbm->colortable32[k].g |= (ilbm->colortable32[k].g >> 4);
  396.             ilbm->colortable32[k].b |= (ilbm->colortable32[k].b >> 4);
  397.             }
  398.         }
  399.         }
  400.  
  401.     /* Now scale to 32 bits */
  402.     for(k = 0; k <nc; k++)
  403.         {
  404.         gun = ilbm->colortable32[k].r;
  405.         ilbm->colortable32[k].r |= ((gun << 24) | (gun << 16) | (gun << 8));
  406.         gun = ilbm->colortable32[k].g;
  407.         ilbm->colortable32[k].g |= ((gun << 24) | (gun << 16) | (gun << 8));
  408.         gun = ilbm->colortable32[k].b;
  409.         ilbm->colortable32[k].b |= ((gun << 24) | (gun << 16) | (gun << 8));
  410.         }
  411.     }
  412.  
  413.     /* always make old-style table */
  414.     rgb = sp->sp_Data;
  415.     ncolors = nc;
  416.     k = 0;
  417.     while (ncolors--) 
  418.          {
  419.          r = (*rgb++ & 0xF0) << 4;
  420.          g = *rgb++ & 0xF0;
  421.          b = *rgb++ >> 4;
  422.          ilbm->colortable[k] = r | g | b;
  423.          k++;
  424.          }
  425.     return(0);
  426.     }
  427.  
  428.  
  429. /* setcolors - sets vp to ilbm->colortable or ilbm->colortable32
  430.  *
  431.  * V39 and above: unless ilbm->IFFPFlags & IFFPF_NOCOLOR32, will
  432.  *  use 32-bit per gun colortable (ilbm->colortable32) and functions
  433.  *
  434.  * Returns client error if there is no ilbm->vp
  435.  */ 
  436. LONG setcolors(struct ILBMInfo *ilbm, struct ViewPort *vp)
  437.     {
  438.     LONG nc;
  439.     LONG error = 0L;
  440.  
  441.     if(!(vp))   return(CLIENT_ERROR);
  442.  
  443.     nc = MIN(ilbm->ncolors,vp->ColorMap->Count);
  444.     if((GfxBase->lib_Version >= 39)&&
  445.         (! (ilbm->IFFPFlags & IFFPF_NOCOLOR32))&&
  446.             (ilbm->colorrecord))
  447.     {
  448.     LoadRGB32(vp, (ULONG *)ilbm->colorrecord);
  449.     }
  450.     else if(ilbm->colortable)
  451.     {
  452.     LoadRGB4(vp, (UWORD *) ilbm->colortable, nc);
  453.     }
  454.     error = CLIENT_ERROR;
  455.     return(error);
  456.     }
  457.  
  458.  
  459. /*
  460.  * Returns CAMG or computed mode for storage in ilbm->camg
  461.  *
  462.  * ilbm->Bmhd structure must be initialized prior to this call.
  463.  */
  464. ULONG getcamg(struct ILBMInfo *ilbm)
  465.     {
  466.     struct IFFHandle *iff;
  467.     struct StoredProperty *sp;
  468.     UWORD  wide,high,deep;
  469.     ULONG modeid = 0L;
  470.  
  471.         if(!(iff=ilbm->ParseInfo.iff))  return(0L);
  472.  
  473.     wide = ilbm->Bmhd.pageWidth;
  474.     high = ilbm->Bmhd.pageHeight;
  475.     deep = ilbm->Bmhd.nPlanes;
  476.  
  477.     D(bug("Getting CAMG for pic w=%ld h=%ld d=%ld ILBM\n",wide,high,deep));
  478.  
  479.         /*
  480.          * Grab CAMG's idea of the viewmodes.
  481.          */
  482.         if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
  483.                 {
  484.                 modeid = (* (ULONG *) sp->sp_Data);
  485.  
  486.         D(bug("Found CAMG containing $%08lx\n",modeid));
  487.  
  488.                 /* knock bad bits out of old-style 16-bit viewmode CAMGs
  489.                  */
  490.                 if((!(modeid & MONITOR_ID_MASK))||
  491.           ((modeid & EXTENDED_MODE)&&(!(modeid & 0xFFFF0000))))
  492.                    modeid &= 
  493.             (~(EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE));
  494.  
  495.         D(bug("Filter1: CAMG now $%08lx\n",modeid));
  496.  
  497.                 /* check for bogus CAMG like DPaintII brushes
  498.                  * with junk in upper word and extended bit
  499.                  * not set in lower word.
  500.                  */
  501.                 if((modeid & 0xFFFF0000)&&(!(modeid & 0x00001000))) sp=NULL;
  502.  
  503.         D(bug("Filter2: CAMG is %s\n", sp ? "OK" : "NOT OK"));
  504.  
  505.                 }
  506.  
  507.         if(!sp) {
  508.                 /*
  509.                  * No CAMG (or bad CAMG) present; use computed modes.
  510.                  */
  511.         modeid = 0L;        /* added in 39.6 */
  512.                 if (wide >= 640)        modeid = HIRES;
  513.                 if (high >= 400)        modeid |= LACE;
  514.                 if (deep == 6)
  515.                         {
  516.                         modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
  517.                         }
  518.         D(bug("No CAMG found - using mode $%08lx\n",modeid));
  519.                 }
  520.  
  521.     if(ilbm->IFFPFlags & IFFPF_NOMONITOR) modeid &= (~MONITOR_ID_MASK);
  522.  
  523.     D(bug("getcamg: modeid = $%08lx\n",modeid));
  524.     return(modeid);
  525.     }
  526.  
  527.