home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CColorBitMap / CColorBitMap.cp < prev    next >
Encoding:
Text File  |  1994-11-30  |  19.3 KB  |  811 lines  |  [TEXT/KAHL]

  1. /*************************************************************************
  2.  Apple Macintosh Developer Technical Support
  3.  
  4.  Some of Forrest Tanaka's Famous High Level Off-Screen Map Routines
  5.  [ Reference: Macintosh Technical Note #120 ]
  6.  
  7.  "CColorBitMap.cp"
  8.  
  9.  These routines provide a high-level interface to the QuickDraw & Color
  10.  Manager routines which allow the creation and manipulation of off-screen
  11.  bitmaps and pixmaps. They are designed to run on any machine with 128K or
  12.  later ROMs.
  13.  
  14.  NOTE that I've modified some of Forrest's routines for the OOP world
  15.        and, therefore, any resultant errors belong solely to me.
  16.  
  17.  using Symantec's "THINK C / C++", v 6/7
  18.  *************************************************************************/
  19.  
  20.  
  21.  
  22.  
  23. #include <CView.h>
  24. #include <Exceptions.h>            /* Has declaration of "kSilentErr" */
  25. #include <TCLUtilities.h>        /* ... and SetAllocation().           */
  26. #include <GestaltEqu.h>
  27. #include <LongQD.h>
  28. #include <OSChecks.h>
  29. #include <Traps.h>
  30.  
  31. #include <Global.h>
  32. #include "CColorBitMap.h"
  33.  
  34.  
  35. extern short        gLastError;
  36.  
  37.  
  38.  
  39.     /*
  40.     ** Call:
  41.     **
  42.     **        FailOSErr( error );
  43.     **
  44.     ** which <IF error ≠ noErr> then calls:
  45.     **
  46.     **        Failure( error, message = 0 );
  47.     **
  48.     ** which sets gLastError = error and gLastMessage = message
  49.     ** AND via your TRY-CATCH-ENDTRY Macros propagates the error
  50.     ** up to the TRY-CATCH-ENDTRY Handlers within CApplication::Run().
  51.     ** The latter's CATCH Handler will call:
  52.     **
  53.     **        if (gLastError != kSilentErr)        // kSilentErr = 0.
  54.     **            ErrorAlert( gLastError, gLastMessage );
  55.     **
  56.     ** and then RETRY what you have in your TRY Macro or Handler.
  57.     ** Because FailOSErr passed a message = 0 to Failure, ErrorAlert
  58.     ** will look for a 'Estr' resource with an ID = the passed error.
  59.     */
  60.  
  61.     static void        ErrorOut (OSErr error)
  62.     {
  63.         FailOSErr( error );
  64.  
  65.     }    /* ErrorOut */
  66.  
  67.  
  68.  
  69. /**************************
  70.  Just plain nifty stuff ...
  71.  **************************/
  72.  
  73. void    CColorBitMap::IColorBitMap (short width, short height, Boolean makePort)
  74. {
  75.         Rect            theBounds;
  76.         long            qdVersion, tempSeed;
  77.         OSErr            err;
  78.         Boolean            depthIndexed, depthDirect, qd32BitInstalled, savedAlloc;
  79.         short            maxDepth, offRowBytes;
  80.         unsigned long    sizeOfOff;
  81.  
  82.  
  83.  /*
  84.     NOTE: I will ignore "makePort" because my bitMap/pixMap
  85.            is intricately tied to the off-screen Port.
  86.  */
  87.             
  88.  /*
  89.     I don't think so !!!!!
  90.     
  91.     MoveHHi( (Handle)this );
  92.     HLock( (Handle)this );
  93.  */
  94.  
  95.     /* Initialize some stuff ... */
  96.     
  97.     xferMode     = srcCopy;
  98.     macPort         = nil;
  99.     macBitMap     = nil;
  100.     itsPixMap     = nil;
  101.     macBits         = nil;
  102.     itsColors     = nil;
  103.     itsMaxDevice = nil;
  104.     
  105.     SetRect( &theBounds, 0, 0, width, height );
  106.     
  107.  /* ErrorOut( noErr );    --    We hope !! */
  108.  
  109.     GetPort( &savePort );                    /* Also used by superclass'
  110.                                                BeginDrawing & EndDrawing. */
  111.     if (!gSystem.hasColorQD)
  112.     {
  113.         savedAlloc = SetAllocation( kAllocCanFail );
  114.         macPort = (GrafPtr) NewPtrClear( sizeof(GrafPort) );
  115.         SetAllocation( savedAlloc );
  116.         if (macPort == nil)
  117.         {
  118.             ErrorOut( NewPortError );
  119.          /*
  120.          ** return;   --   ErrorOut will automatically pop the return
  121.          **                   address off the Stack when FailOSErr is called.
  122.          */
  123.         }
  124.         OpenPort( macPort );
  125.         maxDepth = 1;
  126.         
  127.     }   /* ... a low-life machine */
  128.     
  129.     else
  130.     {
  131.         /* Initialize this guy: */
  132.         savedAlloc = SetAllocation( kAllocCanFail );
  133.         macPort = (GrafPtr) NewPtrClear( sizeof(CGrafPort) );
  134.         SetAllocation( savedAlloc );
  135.         if (macPort == nil)
  136.         {
  137.             ErrorOut( NewPortError );
  138.         }
  139.         OpenCPort( (CGrafPtr)macPort );
  140.         itsPixMap = ((CGrafPtr) macPort)->portPixMap;
  141.      /*
  142.         When we call _CopyBits within our CopyFrom
  143.         and CopyTo methods we pass:
  144.         
  145.             &((GrafPtr) macPort)->portBits;
  146.         
  147.         which is really a Pointer to a PixMapHandle.
  148.         _CopyBits recognizes that and does the
  149.         appropriate de-referencing.  As a result,
  150.         this Handle can float.
  151.         
  152.         MoveHHi( (Handle)itsPixMap );
  153.         HLock( (Handle)itsPixMap );
  154.      */
  155.         
  156.         maxDepth = (**itsPixMap).pixelSize;
  157.         
  158.         if ( TrapAvailable(_Gestalt) )
  159.         {
  160.             Gestalt( gestaltQuickdrawVersion, & qdVersion );
  161.             qd32BitInstalled = qdVersion >= gestalt32BitQD;
  162.         }
  163.         else
  164.             qd32BitInstalled = FALSE;
  165.             
  166.         depthIndexed = maxDepth <= 8;
  167.         depthDirect = (maxDepth > 8) && qd32BitInstalled;
  168.         
  169.         if ( !depthIndexed && !depthDirect )
  170.         {
  171.             SetPort( savePort );
  172.             ErrorOut( DepthError );
  173.         }
  174.  
  175.     };   /* else: hasColorQD */
  176.  
  177.  /*
  178.      Before we do ANYthing more, we should set the off-screen's
  179.      visRgn to the FULL size of the input rect so the image stays
  180.     whole even when the window has been dragged partly beyond
  181.     the physical edge(s) of the screen.  Otherwise, the
  182.     (**visRgn).rgnBBox in local coordinates remains equal to
  183.     screenBits.bounds as initialized when _Open(C)Port was called:
  184.  */
  185.  
  186.     RectRgn( macPort->visRgn, &theBounds );
  187.     macPort->portRect = theBounds;
  188.     ClipRect( &theBounds );
  189.  
  190.  /*
  191.     We are now ready to calculate the size of the pixel image we will need.
  192.     Then we can set the location-specific and size-specific information of
  193.     the pixel map by calling SetupPixMap if we have color or stuffing
  194.     directly if in black-and-white.
  195.  */
  196.  
  197.     /* # of words: */
  198.     offRowBytes = (maxDepth * (theBounds.right - theBounds.left) + 15) / 16;
  199.     if (offRowBytes % 2)    offRowBytes++;        /* ... made even. */
  200.     offRowBytes *= 2;                            /* Back to bytes. */
  201.     if (offRowBytes > kMaxRowBytes)
  202.     {
  203.         SetPort( savePort );
  204.         ErrorOut( MaxRowBytesError );
  205.     }
  206.     
  207.     sizeOfOff = (theBounds.bottom - theBounds.top) * (unsigned long)offRowBytes;
  208.  
  209.     /* Allocate space for the pixel image: */
  210.     savedAlloc = SetAllocation( kAllocCanFail );
  211.     ReserveMem( sizeOfOff );                    /* Around forever !!! */
  212.     macBits = NewHandleClear( sizeOfOff );
  213.     SetAllocation( savedAlloc );
  214.     if (macBits == nil)
  215.     {
  216.         SetPort( savePort );
  217.         ErrorOut( NewBaseAddrPtrError );        /* Bye-Bye !!! */
  218.     }
  219.     HLock( macBits );
  220.  
  221.  /*
  222.      NOTE that we're filling in the BitMap/PixMap fields of the new Port
  223.     directly, so we do NOT call _SetPortBits or _SetCPortPix later:
  224.  */
  225.  
  226.     if (gSystem.hasColorQD)
  227.     {
  228.         itsColors = SetupPixMap( itsPixMap, macBits, offRowBytes, &theBounds );
  229.         if (itsColors == nil)
  230.         {
  231.             SetPort( savePort );
  232.             ErrorOut( ColorTableError );
  233.         }
  234.         
  235.         itsMaxDevice = CreateGDevice( itsPixMap );
  236.         if (itsMaxDevice == nil)
  237.         {
  238.             SetPort( savePort );
  239.             ErrorOut( CreateGDeviceError );
  240.         }
  241.  
  242.      /*
  243.         We effectively pass "itsPixMap" to _CopyBits with:
  244.         
  245.             &((GrafPtr) macPort)->portBits;
  246.             
  247.         In this manner, we avoid having to HLock "itsPixMap".
  248.         
  249.         macBitMap = (BitMapPtr) *itsPixMap;
  250.      */
  251.      
  252.     }   /* if aMac2 */
  253.  
  254.     else   /* definitely ... "YUCKY" black-and-white. */
  255.     {
  256.         macPort->portBits.baseAddr = *macBits;
  257.         macPort->portBits.rowBytes = offRowBytes;
  258.         macPort->portBits.bounds   = theBounds;
  259.  
  260.      /* macBitMap = &macPort->portBits;  --  also works in B&W. */
  261.     };
  262.  
  263.     SetPort( savePort );
  264.     
  265.     CView::ForceNextPrepare();
  266.  
  267.     ErrorOut ( noErr );                                /* Whew !! */
  268.  
  269. }    /* IColorBitMap */
  270.  
  271.  
  272.  
  273. /****************************
  274.  Out with the new.
  275.  
  276.  Whoops -- I meant the old !!
  277.  **************************** */
  278.  
  279. /* OVERRIDE: */
  280. void    CColorBitMap::Dispose (void)
  281. {
  282.  
  283.     if (macPort != nil)
  284.     {
  285.         if (gSystem.hasColorQD)
  286.         {
  287.             if (itsColors /* ≠ nil */)    DisposCTable( itsColors );
  288.          /* HUnlock( (Handle)itsPixMap ); */
  289.             CloseCPort( (CGrafPtr)macPort );
  290.             
  291.             if (itsMaxDevice)
  292.             {
  293.                 /* OH-OH !!!!! */
  294.                 DisposHandle( (Handle) (**itsMaxDevice).gdITable );
  295.                 DisposHandle( (Handle)itsMaxDevice );
  296.             }
  297.         }
  298.         else    /* Yucky B&W */
  299.         {
  300.             ClosePort( macPort );
  301.         }
  302.  
  303.         DisposPtr( (Ptr)macPort );
  304.         macPort = nil;                /* So Dispose() below doesn't try to do       */
  305.                                     /* it again.  Otherwise, BIG time bomb !!! */
  306.     }    /* macPort ≠ nil */
  307.  
  308.     if (macBits)
  309.     {
  310.         HUnlock( macBits );
  311.         DisposHandle( macBits );
  312.         macBits = nil;
  313.     }
  314.     ;
  315.     macBitMap = nil;                /* No need to repeat yourself !! */
  316.  
  317.     CBitMap::Dispose();                /* Kiss him good-bye !! */
  318.     
  319. }    /* Dispose */
  320.  
  321.  
  322.  
  323. void    CColorBitMap::Update (void)
  324. {
  325.     /* NEVER called when gSystem.hasColorQD = FALSE. */
  326.  
  327.         CColorBitMap        *updatedBitMap = NULL;
  328.         LongRect            boundsRect;
  329.         Rect                boundsR;
  330.         RGBColor            aBlackColor = {0x0000, 0x0000, 0x0000},
  331.                             aWhiteColor = {0xFFFF, 0xFFFF, 0xFFFF};
  332.         
  333.     TRY
  334.     {
  335.         updatedBitMap = new (CColorBitMap);
  336.         GetBounds( &boundsRect );
  337.         updatedBitMap->IColorBitMap( (short) (boundsRect.right  - boundsRect.left),
  338.                                      (short) (boundsRect.bottom - boundsRect.top ),
  339.                                      TRUE );
  340.     }
  341.     CATCH
  342.     {
  343.         if (updatedBitMap)        updatedBitMap->Dispose();
  344.     }
  345.     ENDTRY;
  346.             
  347.     /*
  348.         All this just 'cause I haven't YET!!! figured out
  349.         how to update the bits covered by my Objects.
  350.     */
  351.     
  352.     updatedBitMap->BeginDrawing();
  353.     ;
  354.     RGBForeColor( &aBlackColor );
  355.     RGBBackColor( &aWhiteColor );
  356.     LongToQDRect( &boundsRect, &boundsR );
  357.     /*
  358.         See within IColorBitMap that "macPort" = GrafPtr.
  359.         Therefore, it need NOT be typecast:
  360.     */
  361.     CopyBits( &(/*(GrafPtr)*/ this->macPort)->portBits,
  362.               &updatedBitMap->macPort->portBits,
  363.               &boundsR, &boundsR,
  364.               xferMode, NULL );
  365.     ;
  366.     updatedBitMap->EndDrawing();
  367.     
  368.     /*
  369.         Then, dispose of the instance variables of THIS object
  370.         and finally reset these variables to the updated ones:
  371.         
  372.         <it couldn't get much simpler than this !!!>
  373.     */
  374.     
  375.     if (macPort != nil)
  376.     {
  377.         if (itsColors)            DisposCTable( itsColors );
  378.      /* HUnlock( (Handle)itsPixMap ); */
  379.         CloseCPort( (CGrafPtr)macPort );
  380.             
  381.         if (itsMaxDevice)        DisposHandle( (Handle)itsMaxDevice );
  382.  
  383.         DisposPtr( (Ptr)macPort );
  384.  
  385.     }    /* macPort ≠ nil */
  386.  
  387.     if (macBits)
  388.     {
  389.         HUnlock( macBits );
  390.         DisposHandle( macBits );
  391.     }
  392.     
  393.     macPort         = updatedBitMap->macPort;
  394.     itsPixMap     = updatedBitMap->itsPixMap;
  395.     macBits         = updatedBitMap->macBits;
  396.     itsColors     = updatedBitMap->itsColors;
  397.     itsMaxDevice = updatedBitMap->itsMaxDevice;
  398.     macBitMap     = updatedBitMap->macBitMap;
  399.     
  400.     /*
  401.         So far, we've transferred the pertinent variables
  402.         from the new updated CBitMap to the old.  In addition,
  403.         we've kept the old object (= THIS); however, we still
  404.         need to trash the new object reference:
  405.     */
  406.     
  407.     delete( updatedBitMap );        /* = CObject::Dispose() */
  408.  
  409. }    /* Update */
  410.  
  411.  
  412.  
  413. /* OVERRIDE: */
  414. Boolean        CColorBitMap::PixelIsBlack (LongPt *pixelPos)
  415. {
  416.     /*
  417.         This method is overriden SOLELY because I need
  418.         to avoid all reference to "macBitMap" in order
  419.         to NOT have to HLock the "itsPixMap":
  420.     */
  421.     
  422.         short        hPos, vPos;
  423.         long        bitNum;
  424.         LongRect    bounds;
  425.         BitMapPtr    theBitMap;
  426.         
  427.     
  428.     GetBounds( &bounds );
  429.     if ( !PtInLongRect(pixelPos, &bounds) )
  430.         return    (FALSE);        /* Point is not in bitmap. */
  431.         
  432.     if (gSystem.hasColorQD)
  433.         theBitMap = (BitMapPtr) *itsPixMap;        /* Nothing below moves memory. */
  434.     else
  435.         theBitMap = &thePort->portBits;
  436.     
  437.     hPos = pixelPos->h - theBitMap->bounds.left;
  438.     vPos = pixelPos->v - theBitMap->bounds.top;
  439.     
  440.     /*
  441.         Point is within BitMap.  Convert point into
  442.         a bit offset from the start of the image:
  443.     */
  444.     
  445.     bitNum = (long)vPos * theBitMap->rowBytes * 8L + hPos;
  446.     return    ( BitTst(theBitMap->baseAddr, bitNum) );
  447.         
  448. }    /* PixelIsBlack */
  449.  
  450.  
  451.  
  452. /* OVERRIDE: */
  453. void    CColorBitMap::BeginDrawing (void)
  454. {
  455.     /*
  456.         This first "if-else" clause simply duplicates
  457.         CBitMap's BeginDrawing with the exception that
  458.         it addresses color QuickDraw and avoids any
  459.         reference to "macBitMap":
  460.     */
  461.     
  462.     if (macPort == NULL)
  463.     {
  464.         if (gSystem.hasColorQD)
  465.         {
  466.             savePixMap = ((CGrafPtr) thePort)->portPixMap;
  467.             SetPortPix( itsPixMap );
  468.         }
  469.         else
  470.         {
  471.             saveBitMap = thePort->portBits;
  472.             SetPortBits( &macPort->portBits );
  473.         }
  474.     }
  475.     else
  476.     {
  477.         GetPort( &savePort );
  478.         SetPort( macPort );
  479.     }
  480.  
  481.     if (gSystem.hasColorQD)
  482.     {
  483.         saveDevice = GetGDevice();
  484.         SetGDevice( itsMaxDevice );
  485.     }
  486.  
  487. }    /* BeginDrawing*/
  488.  
  489.  
  490.  
  491. /*******************
  492.  Back to "Square 1":
  493.  *******************/
  494.  
  495. /* OVERRIDE: */
  496. void    CColorBitMap::EndDrawing (void)
  497. {
  498.  
  499.     if (macPort == NULL)
  500.     {
  501.         if (gSystem.hasColorQD)
  502.             SetPortPix( savePixMap );
  503.         else
  504.             SetPortBits( &saveBitMap );
  505.     }
  506.     else
  507.     {
  508.         SetPort( savePort );
  509.     }
  510.     
  511.     if (gSystem.hasColorQD)        SetGDevice( saveDevice );
  512.  
  513. }    /* EndDrawing*/
  514.  
  515.  
  516.  
  517. /* OVERRIDE: */
  518. void    CColorBitMap::CopyFrom (LongRect *fromRect, LongRect *toRect,
  519.                                RgnHandle maskRgn)
  520. {
  521.         RGBColor    saveForeColor, saveBackColor,
  522.                     aBlackColor = {0x0000, 0x0000, 0x0000},
  523.                     aWhiteColor = {0xFFFF, 0xFFFF, 0xFFFF};
  524.     
  525.     if (gSystem.hasColorQD)
  526.     {
  527.         GetForeColor( &saveForeColor );
  528.         GetBackColor( &saveBackColor );
  529.         ;
  530.         RGBForeColor( &aBlackColor );
  531.         RGBBackColor( &aWhiteColor );
  532.     }
  533.     
  534.     LCopyBits( &macPort->portBits,
  535.                &thePort->portBits,
  536.                fromRect, toRect,
  537.                xferMode, maskRgn );
  538.     
  539.     if (gSystem.hasColorQD)
  540.     {
  541.         RGBForeColor( &saveForeColor );
  542.         RGBBackColor( &saveBackColor );
  543.     }
  544.     
  545. }    /* CopyFrom */
  546.  
  547.  
  548.  
  549. /* OVERRIDE: */
  550. void    CColorBitMap::CopyTo (LongRect *fromRect, LongRect *toRect,
  551.                              RgnHandle maskRgn)
  552. {
  553.         RGBColor    aBlackColor = {0x0000, 0x0000, 0x0000},
  554.                     aWhiteColor = {0xFFFF, 0xFFFF, 0xFFFF};
  555.     
  556.     /*
  557.         Set the blasted Port to off-screen:
  558.         ( Thanks to America Online )
  559.     */
  560.     BeginDrawing();
  561.     ;
  562.     if (gSystem.hasColorQD)
  563.     {
  564.      /*
  565.          Since the destination is our off-screen pixmap,
  566.          we do NOT need to restore the old foreground
  567.          and background colors as we did within CopyFrom:
  568.          
  569.         GetForeColor( &saveForeColor );
  570.         GetBackColor( &saveBackColor );
  571.      */
  572.         RGBForeColor( &aBlackColor );
  573.         RGBBackColor( &aWhiteColor );
  574.     }
  575.     
  576.     LCopyBits( &thePort->portBits,
  577.                &macPort->portBits,
  578.                fromRect, toRect,
  579.                xferMode, maskRgn );
  580.     ;
  581.     EndDrawing();        /* Restore status quo. */
  582.     
  583. }    /* CopyTo */
  584.  
  585.  
  586.  
  587. /* OVERRIDE: */
  588. void    CColorBitMap::GetBounds (LongRect *theBounds)
  589. {
  590.     /* Once again, just to avoid having to HLock "itsPixMap": */
  591.     
  592.         Rect    itsBounds;
  593.         
  594.         
  595.     if (gSystem.hasColorQD)
  596.         itsBounds = (**itsPixMap).bounds;
  597.     else
  598.         itsBounds = macPort->portBits.bounds;
  599.         
  600.     QDToLongRect( &itsBounds, theBounds );
  601.     
  602. }    /* GetBounds */
  603.  
  604.  
  605.  
  606. /* OVERRIDE: */
  607. void    CColorBitMap::SetBoundsOrigin (short hOrigin, short vOrigin)
  608. {
  609.         LongRect    newLBounds;
  610.         Rect        newSBounds;
  611.         
  612.         
  613.     if ( gSystem.hasColorQD && (!itsPixMap || !itsMaxDevice) )
  614.         /* Don't even try!!! */
  615.         return;
  616.         
  617.     GetBounds( &newLBounds );
  618.     
  619.     /* CBitMap::SetBoundsOrigin(...): */
  620.     newLBounds.right  += hOrigin - newLBounds.left;
  621.     newLBounds.bottom += vOrigin - newLBounds.top;
  622.     newLBounds.left       = hOrigin;
  623.     newLBounds.top       = vOrigin;
  624.     ;
  625.     LongToQDRect( &newLBounds, &newSBounds );
  626.     
  627.     RectRgn( macPort->visRgn, &newSBounds );
  628.     macPort->portRect = newSBounds;
  629.     RectRgn( macPort->clipRgn, &newSBounds );
  630.     if (gSystem.hasColorQD)
  631.     {
  632.         (**itsPixMap).bounds = newSBounds;
  633.      /* (**itsMaxDevice).gdPMap = itsPixMap; */
  634.         (**itsMaxDevice).gdRect = newSBounds;
  635.     }
  636.     else
  637.     {
  638.         macPort->portBits.bounds = newSBounds;
  639.     }
  640.     
  641. }    /* SetBoundsOrigin */
  642.  
  643.  
  644.  
  645. /* PRIVATE: */
  646. CTabHandle    CColorBitMap::SetupPixMap (PixMapHandle aPixMap, Handle imageBits,
  647.                                       short bytesPerRow, Rect *theBounds)
  648. {
  649.         CTabHandle        newColors;        /* Color table used for        */
  650.                                         /*   the off-screen PixMap. */
  651.         short            depth;
  652.         Boolean            savedAlloc;
  653.         OSErr            error;
  654.  
  655.  
  656.     newColors = nil;
  657.     depth = (**aPixMap).pixelSize;
  658.  
  659.     /* Clone the clut if indexed color; allocate a dummy clut if direct color: */
  660.     savedAlloc = SetAllocation( kAllocCanFail );
  661.     ;
  662.     if (depth <= 8)
  663.     {
  664.         newColors = (**aPixMap).pmTable;
  665.         error = HandToHand( (Handle*)&newColors );
  666.     }
  667.     else
  668.     {
  669.         newColors = (CTabHandle) NewHandleClear( sizeof(ColorTable) -
  670.                                                  sizeof(CSpecArray) );
  671.         error = MemError();
  672.     }
  673.     ;
  674.     SetAllocation( savedAlloc );
  675.  
  676.     if (error != noErr)
  677.     {
  678.         return    (nil);
  679.     }
  680.  
  681.     /* Initialize fields common to indexed and direct PixMaps: */
  682.     (**aPixMap).baseAddr   = *imageBits;            /* Point to image.           */
  683.     (**aPixMap).rowBytes   = bytesPerRow | 0x8000;    /* MSB set for PixMap.       */
  684.     (**aPixMap).bounds       = *theBounds;
  685.     (**aPixMap).pmVersion  = 0;                        /* No special stuff.       */
  686.     (**aPixMap).packType   = 0;                        /* Default PICT pack.       */
  687.     (**aPixMap).packSize   = 0;                        /* Always zero in memory.  */
  688.     (**aPixMap).hRes       = kDefaultRes;            /* 72 DPI default res.       */
  689.     (**aPixMap).vRes       = kDefaultRes;            /* 72 DPI default res.       */
  690.  /* (**aPixMap).pixelSize  = depth;                    -- Already done.           */
  691.     (**aPixMap).planeBytes = 0;                        /* Not used.               */
  692.     (**aPixMap).pmReserved = 0;                        /* Not used.               */
  693.  
  694.     /* Initialize fields specific to indexed and direct PixMaps: */
  695.     if (depth <= 8)
  696.     {
  697.         (**aPixMap).pixelType = 0;                    /* Indicates indexed.       */
  698.         (**aPixMap).cmpCount  = 1;                    /* Have 1 component.       */
  699.         (**aPixMap).cmpSize   = depth;                /* Component size = depth. */
  700.         (**aPixMap).pmTable   = newColors;            /* Handle to CLUT.           */
  701.     }
  702.     else
  703.     {
  704.         (**aPixMap).pixelType    = RGBDirect;        /* Indicates direct.       */
  705.         (**aPixMap).cmpCount    = 3;                /* Have 3 components.       */
  706.         if (depth == 16)
  707.             (**aPixMap).cmpSize    = 5;                /* 5 bits/component.       */
  708.         else
  709.             (**aPixMap).cmpSize    = 8;                /* 8 bits/component.       */
  710.         (**newColors).ctSeed    = 3 * (**aPixMap).cmpSize;
  711.         (**newColors).ctFlags    = 0;
  712.         (**newColors).ctSize    = 0;
  713.         (**aPixMap).pmTable        = newColors;
  714.     }
  715.     
  716.     return    (newColors);
  717.  
  718. }    /* SetupPixMap*/
  719.  
  720.  
  721.  
  722. /* PRIVATE: */
  723. GDHandle    CColorBitMap::CreateGDevice (PixMapHandle basePixMap)
  724. {
  725.         GDHandle        newDevice;        /* Handle to the new GDevice.              */
  726.         ITabHandle        embryoITab;        /* Handle to the embryonic inverse table. */
  727.         Boolean            savedAlloc;
  728.         Rect            deviceRect;        /* Rectangle of GDevice.                  */
  729.         short            depth;
  730.  
  731.  
  732.     /* Initialize a few things before we begin: */
  733.     newDevice = nil;
  734.     embryoITab = nil;
  735.  
  736.     /* Allocate memory for the new GDevice: */
  737.     savedAlloc = SetAllocation( kAllocCanFail );
  738.     newDevice = (GDHandle) NewHandleClear( sizeof(GDevice) );
  739.     SetAllocation( savedAlloc );
  740.     if (newDevice != nil)    
  741.     {
  742.     
  743.         /* Allocate the embryonic inverse table: */
  744.         savedAlloc = SetAllocation( kAllocCanFail );
  745.         embryoITab = (ITabHandle) NewHandleClear( 2L );
  746.         SetAllocation( savedAlloc );
  747.         if (embryoITab == nil)
  748.         {
  749.             DisposHandle( (Handle)newDevice );
  750.             return    (nil);
  751.         }
  752.         
  753.         /* Set rectangle of device to PixMap bounds: */
  754.         deviceRect = (**basePixMap).bounds;
  755.         
  756.         depth = (**basePixMap).pixelSize;
  757.  
  758.         /* Initialize the new GDevice fields: */
  759.         (**newDevice).gdRefNum       = 0;                /* Only used for screens.     */
  760.         (**newDevice).gdID           = 0;                /* Won’t normally use.         */
  761.         if (depth <= 8)
  762.             (**newDevice).gdType   = clutType;        /* Depth ≤ 8; clut device.     */
  763.         else
  764.             (**newDevice).gdType   = directType;    /* Depth > 8; direct device. */
  765.         (**newDevice).gdITable       = embryoITab;    /* 2-byte handle for now.     */
  766.         (**newDevice).gdResPref       = kITabRes;        /* Normal inv table res.     */
  767.         (**newDevice).gdSearchProc = nil;            /* No color-search proc.     */
  768.         (**newDevice).gdCompProc   = nil;            /* No complement proc.         */
  769.         (**newDevice).gdFlags       = 0;                /* Will set these below.     */
  770.         (**newDevice).gdPMap       = basePixMap;    /* Reference our PixMap.     */
  771.         (**newDevice).gdRefCon       = 0;                /* Won’t normally use.         */
  772.         (**newDevice).gdNextGD       = nil;            /* Not in GDevice list.         */
  773.         (**newDevice).gdRect       = deviceRect;    /* Use PixMap dimensions.     */
  774.         (**newDevice).gdMode       = -1;            /* For non-screens.             */
  775.         (**newDevice).gdCCBytes       = 0;                /* Only used for screens.     */
  776.         (**newDevice).gdCCDepth       = 0;                /* Only used for screens.     */
  777.         (**newDevice).gdCCXData       = 0;                /* Only used for screens.     */
  778.         (**newDevice).gdCCXMask       = 0;                /* Only used for screens.     */
  779.         (**newDevice).gdReserved   = 0;                /* Currently unused.         */
  780.  
  781.         /* Set color-device bit if PixMap isn’t black & white: */
  782.         if (depth > 1)
  783.             SetDeviceAttribute( newDevice, gdDevType, true );
  784.  
  785.         /* Set bit to indicate that the GDevice has no video driver: */
  786.         SetDeviceAttribute( newDevice, noDriver, true );
  787.  
  788.         /* Initialize the inverse table: */
  789.         if (depth <= 8)
  790.         {
  791.             MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable,
  792.                         (**newDevice).gdResPref );
  793.             if ( QDError() != noErr )
  794.             {
  795.                 DisposHandle( (Handle)newDevice );
  796.                 DisposHandle( (Handle)embryoITab );
  797.                 newDevice = nil;
  798.             }
  799.         }
  800.         
  801.     }    /* newDevice != nil */
  802.     
  803.     return    (newDevice);
  804.  
  805. }    /* CreateGDevice*/
  806.  
  807.  
  808.  
  809.  
  810. /* end: "CColorBitMap.cp" */
  811.