home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Snippets / Sideways / MSBitMapLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-22  |  9.1 KB  |  363 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  
  3. This contains a routine to draw rotated text. There are a number of useful
  4. bitmap routines here as well. This code is written to be simple, flexible and 
  5. understandable but is clearly not especially efficient.
  6.  
  7. The usual disclaimers apply: if you use this code and there are errors, you're
  8. on your own. There is no charge for this trifle, and you don't have to reference
  9. me if you use it in an application. If someone is foolish enough to want to 
  10. include this stuff in source code libraries that are for sale, talk to me and 
  11. we'll work something out. 
  12.  
  13. It would be interesting for me if anyone that uses this stuff were to let me know
  14. what you're using it for, but that's up to you. Certainly lemme know if there are
  15. any boo-boos or gotchas so that I can fix them.
  16.  
  17.            Written by Mark Stockwell
  18.                               Compuserve: 76354,2303
  19.                                 AOL:                 MarkS77
  20.                                 Internet:     76354.2303@compuserve.com
  21.                                                         MarkS77@aol.com
  22.  
  23.  ******************************************************************************/
  24.  
  25. #include "MSUtil.h"
  26. #include "MSBitMapLib.h"
  27.  
  28. struct MSTextState {
  29.     int         ftxFont;
  30.     Style        ftxFace;
  31.     int            ftxMode, ftxSize;
  32.     Fixed        fspExtra;
  33.     RGBColor    fForeColor, fBackColor;
  34. };
  35.  
  36. typedef struct MSTextState MSTextState;
  37.  
  38.  
  39. MSTextState MSGetCTextState (
  40.     CGrafPtr    aPort)
  41. {
  42.     RGBColor         theForeColor, theBackColor;
  43.     MSTextState    holdTextState;
  44.  
  45.     holdTextState.ftxFont = (*aPort).txFont;
  46.     holdTextState.ftxFace = (*aPort).txFace;
  47.     holdTextState.ftxMode = (*aPort).txMode;
  48.     holdTextState.ftxSize = (*aPort).txSize;
  49.     holdTextState.fspExtra = (*aPort).spExtra;
  50.     GetForeColor(&theForeColor);
  51.     GetBackColor(&theBackColor);
  52.     holdTextState.fForeColor = theForeColor;
  53.     holdTextState.fBackColor = theBackColor;
  54.     return holdTextState;
  55. }
  56.  
  57. MSTextState MSGetTextState (
  58.     GrafPtr    aPort)
  59. {
  60.     RGBColor         theForeColor, theBackColor;
  61.     MSTextState    holdTextState;
  62.  
  63.     holdTextState.ftxFont = (*aPort).txFont;
  64.     holdTextState.ftxFace = (*aPort).txFace;
  65.     holdTextState.ftxMode = (*aPort).txMode;
  66.     holdTextState.ftxSize = (*aPort).txSize;
  67.     holdTextState.fspExtra = (*aPort).spExtra;
  68.     return holdTextState;
  69. }
  70.  
  71.  
  72. void MSSetTextState (
  73.     MSTextState theState)
  74. {
  75.     TextFont(theState.ftxFont);
  76.     TextFace(theState.ftxFace);
  77.     TextMode(theState.ftxMode);
  78.     TextSize(theState.ftxSize);
  79.     SpaceExtra(theState.fspExtra);
  80.     if (MSColorIndexesOK())
  81.     {
  82.         RGBForeColor(&theState.fForeColor);
  83.         RGBBackColor(&theState.fBackColor);
  84.     }
  85. }
  86.  
  87. void MSEraseBitMap (
  88.     BitMap *theBitMap)
  89. {
  90.         // The srcXor mode erases the bitMap.
  91.     CopyBits(theBitMap, theBitMap, &((*theBitMap).bounds), &((*theBitMap).bounds), srcXor, NULL);
  92. }
  93.  
  94. BitMap *MSNewBitMap (
  95.     short *bitsWide,
  96.     short *bitsHigh)
  97. {
  98.     BitMap        *tempBitMap;
  99.     long    sizeOfImage;
  100.  
  101.     tempBitMap = (BitMap *) NewPtr(sizeof(BitMap));
  102.     if (tempBitMap == NULL)
  103.         return NULL;
  104.         
  105.     tempBitMap->baseAddr = NULL;
  106.  
  107.        // Force bitsWide to be a multiple of 8. 
  108.        // We do this because bitMaps want it this way, just because.
  109.     if (*bitsWide != (*bitsWide / 8) * 8) 
  110.         *bitsWide = ((*bitsWide / 8) + 1) * 8L;
  111.  
  112.     if (*bitsHigh != (*bitsHigh / 8) * 8) 
  113.         *bitsHigh = ((*bitsHigh / 8) + 1) * 8;
  114.  
  115.     SetRect(&(tempBitMap->bounds), 0, 0, *bitsWide, *bitsHigh);
  116.     tempBitMap->rowBytes = (*bitsWide) / 8;
  117.     sizeOfImage = (*bitsWide) * (*bitsHigh);
  118.         tempBitMap->baseAddr = (Ptr)NewPtr(sizeOfImage);
  119.         
  120.         // Didn't get the memory, bail.
  121.     if (tempBitMap->baseAddr == NULL)
  122.     {
  123.         DisposPtr((Ptr)tempBitMap);
  124.         return NULL;
  125.     }
  126.         
  127.         // Give us a clean slate.
  128.     MSEraseBitMap(tempBitMap);
  129.     return tempBitMap;
  130. }
  131.  
  132. void MSDisposeBitMap(
  133.     BitMap *theBitMap)
  134. {
  135.     if (theBitMap->baseAddr != NULL)
  136.         DisposPtr(theBitMap->baseAddr);
  137.     if (theBitMap != NULL)
  138.         DisposPtr((Ptr)theBitMap);
  139. }
  140.  
  141. int MSGoodBitMap (
  142.     BitMap theBitMap)
  143. {
  144.     if (&theBitMap == NULL)
  145.         return 0;
  146.         
  147.     if (theBitMap.baseAddr != NULL) 
  148.         return 1;
  149.     else
  150.         return 0;
  151. }
  152.  
  153. int MSBitIsSet (
  154.     short     x, 
  155.     short     y,
  156.     BitMap    *theBitMap)
  157. {
  158.     long    theIndex;
  159.  
  160.     theIndex = y * (theBitMap->bounds.right - theBitMap->bounds.left) + x;
  161.  
  162.     if (BitTst(theBitMap->baseAddr, theIndex))
  163.         return 1;
  164.     else
  165.         return 0;
  166. }
  167.  
  168. void MSSetTheBit (
  169.     short     x, 
  170.     short     y,
  171.     BitMap    *theBitMap)
  172. {
  173.     long    theIndex;
  174.  
  175.     theIndex = y * (theBitMap->bounds.right - theBitMap->bounds.left) + x;
  176.  
  177.     BitSet(theBitMap->baseAddr, theIndex);
  178. }
  179.  
  180. void MSClearTheBit (
  181.     short     x, 
  182.     short        y,
  183.     BitMap    *theBitMap)
  184. {
  185.     long     theIndex;
  186.  
  187.     theIndex = y * (theBitMap->bounds.right - theBitMap->bounds.left) + x;
  188.  
  189.     BitClr(theBitMap->baseAddr, theIndex);
  190. }
  191.  
  192.  
  193. // Rotate a bitmap....
  194. BitMap *MSBitFlip (
  195.      BitMap    *inMap)
  196. {
  197.     short        x, y, bitsWide, bitsTall;
  198.     BitMap     *outMap;
  199.  
  200.         // Check to see if we got a valid BitMap.
  201.     if (!MSGoodBitMap(*inMap))
  202.     {
  203.         outMap = NULL;
  204.         return;
  205.     }
  206.         
  207.         // How big is this puppy.
  208.     bitsWide = inMap->bounds.right - inMap->bounds.left;
  209.     bitsTall = inMap->bounds.bottom - inMap->bounds.top;
  210.  
  211.         // Make a new bitmap to hold the rotated image.
  212.         // Where the original was wide and tall, this one is tall and wide.
  213.     outMap = MSNewBitMap(&bitsTall, &bitsWide);
  214.     if (!MSGoodBitMap(*outMap)) 
  215.         return NULL; 
  216.     
  217.       // For all the bits set in inMap ( the dark pixels) , set the 
  218.       // appropriate bit in outMap. This can be sped up considerably
  219.       // by 'unwrapping' the BitIsSet and SetTheBit routines, and not
  220.       // recalculating theIndex each time.
  221.     for (y=0; y < bitsTall; y++)
  222.         {
  223.             for (x=0; x < bitsWide; x++)
  224.                 {
  225.                     if (MSBitIsSet(x, y, inMap))
  226.                         MSSetTheBit(y, (bitsWide -1) - x, outMap);
  227.                 }
  228.         }
  229.     return outMap;
  230. }
  231.  
  232.  
  233. void MSDrawRotatedText (
  234.     short     xPixel,
  235.     short        yPixel, 
  236.     Str255    theText)
  237. {
  238.     GrafPort            myPort;
  239.     GrafPtr                oldPortPtr;
  240.     CGrafPtr            oldcPortPtr;
  241.     BitMap                *defaultBitMap, *offscreenBitMap, *rotatedBitMap;
  242.     Rect                    destRect;
  243.     FontInfo            Info;
  244.     short                    bitsTall, bitsWide, padding;
  245.     Boolean                oldPortIsColorPort;
  246.     MSTextState        theTextState;
  247.  
  248.  
  249.         // Figure out how big we need to make our bitmaps.  
  250.         // Add some padding at top and bottom equal to the descent. 
  251.     GetFontInfo(&Info);
  252.     padding = Info.descent;
  253.     bitsTall = Info.ascent + Info.descent + 2 * padding;
  254.     bitsWide = StringWidth(theText) + 2 * padding;
  255.  
  256.  
  257.         // Here's where we create a new bitMap to draw the text into that
  258.         // we're gonna rotate.
  259.     offscreenBitMap = MSNewBitMap(&bitsWide, &bitsTall);
  260.     if (!MSGoodBitMap(*offscreenBitMap))
  261.         return;
  262.  
  263.  
  264.         // Figure out if we're dealing with a color GrafPort or a B&W one.
  265.   if (MSColorIndexesOK())
  266.       oldPortIsColorPort = true;
  267.   else
  268.       oldPortIsColorPort = false;
  269.  
  270.         // We're getting ready to draw offscreen. If we just set the
  271.         // portbits field of the current grafPort to our offscreen
  272.         // bitmap, we'll draw the unrotated text into the current 
  273.         // port (your window), then rotate it and draw the rotated
  274.         // version into your window as well.
  275.         
  276.         // To only draw the rotated text, we must save the original
  277.         // grafPort (the one attached to your window) and create a
  278.         // new grafPort not attached to any window in which to draw
  279.         // offscreen.
  280.         
  281.         
  282.         
  283.         // Here's where we save the grafPort belonging to your 
  284.         // current window. 
  285.         
  286.         // The new grafport gets default values for font, text size, 
  287.         // etc... We need to capture these values from the current 
  288.         // port before creating the new port.
  289.     if (oldPortIsColorPort)
  290.     {
  291.         GetPort( (GrafPtr *)&oldcPortPtr );
  292.         theTextState = MSGetCTextState(oldcPortPtr);
  293.     }
  294.     else
  295.     {
  296.         GetPort( &oldPortPtr );
  297.         theTextState = MSGetTextState(oldPortPtr);
  298.     }
  299.         
  300.  
  301.         
  302.         // Now create the new grafPort in which we'll be drawing offscreen.
  303.     OpenPort(&myPort);
  304.     
  305.         // Set the text state for this port that of the original grafPort. 
  306.     MSSetTextState(theTextState);
  307.     
  308.     
  309.         // Save the default bitmap from our new grafPort. It's probably not
  310.         // the right size.
  311.     defaultBitMap = &(myPort.portBits);
  312.         
  313.         
  314.         // Set the portBits field of the new grafPort to our bitmap instead.
  315.         // QuickDraw will now draw into 'offscreenBitMap', instead of 
  316.         // into 'defaultBitMap'.         
  317.     SetPortBits(offscreenBitMap);
  318.  
  319.  
  320.         // Move right     'padding'             pixels.
  321.         // Move up         'descent+padding'     pixels.
  322.         // Then draw the string.
  323.     MoveTo(padding, bitsTall - Info.descent - padding);
  324.     DrawString(theText);
  325.  
  326.         
  327.         // Restore the old grafPort as the current port.                              
  328.     if (oldPortIsColorPort)
  329.         SetPort( (GrafPtr)oldcPortPtr );
  330.     else
  331.         SetPort( oldPortPtr );
  332.         
  333.         // Give myPort back its default bitmap, and then get
  334.         // rid of the whole thing. The bitmap with our text
  335.         // drawn into it is offscreenBitMap.
  336.     SetPortBits(defaultBitMap);
  337.     ClosePort(&myPort);
  338.  
  339.  
  340.         // This is where the text is actually turned on its side. 
  341.         // The bitmap "rotatedBitMap" is a rotated version of
  342.         // offscreenBitMap.
  343.     rotatedBitMap = MSBitFlip(offscreenBitMap);
  344.     if (!MSGoodBitMap(*rotatedBitMap))
  345.     {
  346.         MSDisposeBitMap(offscreenBitMap);
  347.         return;
  348.     }
  349.  
  350.         // The rotated bitmap is moved into position and drawn into whatever port
  351.         // was active when you called DrawSideWaysText.                                   
  352.     destRect = rotatedBitMap->bounds;
  353.     OffsetRect(&destRect, xPixel - bitsTall + padding + Info.descent, yPixel - bitsWide + padding);
  354.     CopyBits(rotatedBitMap, &((*thePort).portBits), &(rotatedBitMap->bounds), &destRect, srcOr, NULL);
  355.  
  356.  
  357.         // We've still got these two bitmaps we don't need any more.
  358.         // I want my memory back NOW.  
  359.     MSDisposeBitMap(offscreenBitMap);
  360.     MSDisposeBitMap(rotatedBitMap);
  361. }
  362.  
  363.