Newsgroups: comp.sys.mac.programmer
Distribution: world
From: Patrick_J._Toole@uu0570.foggybottom.com
Organization: Foggy Bottom / Washington, D.C.
Date: Wed, 23 Dec 1992 19:32:03 EST
Subject: Re: Code for drawing a sprite desired.

Personally, I'm a Pascal programmer-desperately trying to learn C. Since I
don't program in C, I won't be able to refer to code, but I will attach code
from tech note #41. That's all I use. 

Every window pointer and grafPtr have a bitmap. This is passed as the first
two parameters; the source, then the destination. (In pascal, you'd pass it by
myWindowPtr^.portBits). Then, of course, the rectangles of the ports you wish
to pass. To use the Mask, you need to use CopyMask (if I'm not mistaken). All
it does is just copy the pixels that are the color black in the rectangle
passed by maskRect.

What you want to do is something like this: 
CopyBits(myOffscreen^.portBits, myOffscreen^.portBits, myWindow^.portBits,
OffscreenSourceRect, OffscreenMaskRect, OnScreenRect);

Good Luck!

Write me personally if you have any other questions.
If you want to do it in color, read TN #120.

Excerpt from TN#41:
First, let's look at a general purpose function to create an off-screen
bitmap.  This function creates the GrafPort on the heap.  You could also
create it on the stack and pass the uninitialized structure to a function
similar to this one.

Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
{
  GrafPtr savePort;
  GrafPtr newPort;

  GetPort(&savePort);    /* need this to restore thePort after OpenPort */

  newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */
  if (MemError() != noErr)
    return false;                 /* failed to allocate the off-screen port */
  /*
  the call to OpenPort does the following . . . 
    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set
wide open)
    sets portBits to screenBits
    sets portRect to screenBits.bounds
    etc. (see IM I-163,164)
    side effect: does a SetPort(&offScreen)
  */
  OpenPort(newPort);
  /* make bitmap the size of the bounds that caller supplied */
  newPort->portRect = *inBounds;
  newPort->portBits.bounds = *inBounds;
  RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be
safe  */
  RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen
bounds */

  /* rowBytes is size of row, it must be rounded up to an even number of bytes
*/
  newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4)
<< 1;

  /* number of bytes in BitMap is rowBytes * number of rows */
  /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr */
  newPort->portBits.baseAddr =
           NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom -
inBounds->top));
  if (MemError()!=noErr) {   /* check to see if we had enough room for the
bits */
    SetPort(savePort);
    ClosePort(newPort);      /* dump the visRgn and clipRgn */
    DisposPtr((Ptr)newPort); /* dump the GrafPort */
    return false;            /* tell caller we failed */
    }
  /* since the bits are just memory, let's clear them before we start */
  EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */
  *newOffscreen = newPort;
  SetPort(savePort);
  return true;               /* tell caller we succeeded! */
}

Here is the function to get rid of an off-screen bitmap created by the
previous function:

void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
{
  ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */
  DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */
  DisposPtr((Ptr)oldOffscreen);                  /* dump the port */
}

Now that you know how to create and destroy an off-screen bitmap, let's go through the motions
of using one.  First, let's define a few things to make the _NewWindow call a
little clearer.

#define kIsVisible true
#define kNoGoAway false
#define kNoWindowStorage 0L
#define kFrontWindow ((WindowPtr) -1L)

Here's the body of the test code:

main()
{
  char* myString = "\pThe EYE";  /* string to display */

  GrafPtr   offscreen;           /* our off-screen bitmap */
  Rect      ovalRect;            /* used for example drawing */
  Rect      myWBounds;           /* for creating window */
  Rect      OSRect;              /* portRect and bounds for off-screen
bitmap*/
  WindowPtr myWindow;

  InitToolbox();                 /* exercise for the reader */
  myWBounds = qd.screenBits.bounds;  /* size of main screen */
  InsetRect(&myWBounds, 50,50);  /* make it fit better */
  myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window",
kIsVisible,
                       noGrowDocProc, kFrontWindow, kNoGoAway, 0);
  if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {
    SysBeep(1);
    ExitToShell();
    }
  /* Example drawing to our off-screen bitmap*/
  SetPort(offscreen);
  OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect
*/
  ovalRect = OSRect;
  FillOval(&ovalRect, qd.black);
  InsetRect(&ovalRect, 1, 20);
  FillOval(&ovalRect, qd.white);
  InsetRect(&ovalRect, 40, 1);
  FillOval(&ovalRect, qd.black);
  MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,
         (ovalRect.top + ovalRect.bottom - 12) >> 1);
  TextMode(srcXor);
  DrawString(myString);

  /* copy from the off-screen bitmap to the on-screen window.  Note that in this
  case the source and destination rects are the same size and both cover the
  entire area.  These rects are allowed to be portions of the source and/or
  destination and do not have to be the same size.  If they are not the same
size
  then _CopyBits scales the image accordingly.
  */
  SetPort(myWindow);
  CopyBits(&offscreen->portBits, &(*myWindow).portBits,
           &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);

  DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */
  while (!Button());     /* give user a chance to see our work of art */
}

/* This demonstrates offscreening and copyBits */

I didn't write this, the BBS did:
Foggy Bottom - your FirstClass Mac connection in Washington, DC