[comp.sys.mac.programmer] Aligning Bitmaps

jackiw@cs.swarthmore.edu (Nick Jackiw) (03/07/90)

In Inside Mac V and in various places in the techNotes, it states that CopyBits
is optimized for cases in which rowBytes is a multiple of four and in which
the bitmaps are aligned.  I recently did some testing on a (wide) sample of
arbitrary bitmaps, and came up with the following interesting timings:

o	Worst case ranges from about 102-105% of average case.
	(Which is to say: the average case is about as bad as you can get)
o	Best case (perfect alignment) ranges from about 54-72% of average case.
	(i. e. Alignment has a *substantial* payoff.)

Remember, alignment (keeping the bit-index the same between corresponding
bits in the source bitmap and the destination) is only useful under several
conditions:

o	You're always copying part of the source into one and only one
	corresponding part of the destination.

o	The source and destination are at the same bitdepth, if you're
	working in color.

o	For any given copy, the srcRect and destRect are of the same
	dimension (though not necessarily the same coordinates).

A good example of when alignment is useful: storing an offscreen bitmap
containing the image to be painted into a window.  Alignment will only
change (and the offscreen map be recomputed) if the window is moved.

A good example of when alignment won't help at all: storing the image
of a spaceship offscreen which can be copyBitted anywhere into the window.
("Anywhere"=any of 32 bit positions=alignment will only help you in 1/32
of your copies. Of course, you could store 32 differently-aligned spaceship
copies offscreen, and choose the appropriate one to blit based on the
dest rect.)

-------

The following function might be useful for cases when you want to create
an offscreen bitmap for copying to a window.  Specify the window (which
must already be created and in its proper location) in destWindow, and
the bounds of the desired offscreen window (in the local coordinate 
system of destWindow).  InitAlignedBitmap will generate the bitmap,
tacking enough "slack" onto the left edge of the bitmap (i. e. by extending
the bounds) to guarantee that any bit in theBits is aligned with the
corresponding bit in the window's local coordinate system. This will 
guarantee you best case performance.

------

Lastly, a note or two:

o	If User moves the window, you'll need to recompute and redraw
	the bitmap.  You can dispose the old one and call this function
	again, if you like, or you can modify this one to SetPtrSize
	on the existing baseAddr ptr. You may want to change the code
	to generate handles, instead of ptrs, but remember to lock and
	derefence them before drawing.  Growing a window doesn't change
	the alignment (e. g. local [0,0] is still in the same place as
	it was pre-grow; therefore so is offscreen [0,0].)

o	Color doesn't complicate things (multiply by pixDepth before
	determining rowBytes, and don't forget to set the high bit),
	but multiple screens and multiple pixel depths do. In that you
	can only be in alignment with one of the multiple screens at a
	time (or only *guarantee* that you'll be so), you'll have to
	choose between aligning for the screen which is deepest (which
	you'll want to do if your offscreen bitmap should be complexly
	colored), or for the screen which has the maximum destWindow area
	on it (which will optimize for speed over color fidelity). Once
	you've figured out which GDevice to align to, plug in its pixMap
	for screenBits, below.

Enjoy.

--------

function InitAlignedBitMap(var theBits:Bitmap;destWindow:WindowPtr):boolean;

{By Nick Jackiw}
{Allocates storage for a bitmap the bounds of which have been set before}
{calling.  The bitmap will be long-word aligned with the coordinate system}
{of the bit image which contains the destWindow.}

  var
   oldPort: GrafPtr;
   aPoint: point;
   bitOffset: integer;	{# of bits we need to expand the offscreen map by}

 begin
  GetPort(oldPort);	{Switch to desired port, for local->global conversion}
  SetPort(destWindow);
  aPoint := theBits.bounds.topLeft;
  LocalToGlobal(aPoint);

  bitOffset := (aPoint.h - ScreenBits.bounds.left) mod 32;
  if bitOffset < 0 then
   bitOffset := 32 + bitOffset;

  with theBits.bounds do
   left := left - bitOffset;{Expand dest bitmap by appropriate # of bits}

  with theBits do
   with bounds do
    begin
     rowBytes := ((right - left + 31) div 32) * 4;
     baseAddr := NewPtr(rowBytes * (bottom - top));
     InitAlignedBitMap := baseAddr <> nil
    end;
  SetPort(oldPort)
 end;

--
+-------------------+-jackiw@cs.swarthmore.edu / !rutgers!bpa!swatsun!jackiw-+
|  nicholas jackiw  | jackiw%campus.swarthmore.edu@swarthmr.bitnet           |
+-------------------+-VGP/MathDept/Swarthmore College, Swarthmore, PA 19081--+
"Ah...I've got this CHRONIC pain."                             _True Believer_

pepke@gw.scri.fsu.edu (Eric Pepke) (03/07/90)

In article <S5XF99Q@xavier.swarthmore.edu> jackiw@cs.swarthmore.edu (Nick 
Jackiw) writes:
> A good example of when alignment won't help at all: storing the image
> of a spaceship offscreen which can be copyBitted anywhere into the 
window.
> ("Anywhere"=any of 32 bit positions=alignment will only help you in 1/32
> of your copies. Of course, you could store 32 differently-aligned 
spaceship
> copies offscreen, and choose the appropriate one to blit based on the
> dest rect.)

I sometimes use an intermediate approach for offscreen bitmaps (not 
pixmaps).  I keep an extra longword on the right of the bitmap on each 
row.  When it comes time to plop this on the screen, I preshift the bits 
using a tight assembly loop.  Of course, this only really helps when the 
bitmaps are pretty large.

Eric Pepke                                    INTERNET: pepke@gw.scri.fsu.edu
Supercomputer Computations Research Institute MFENET:   pepke@fsu
Florida State University                      SPAN:     scri::pepke
Tallahassee, FL 32306-4052                    BITNET:   pepke@fsu

Disclaimer: My employers seldom even LISTEN to my opinions.
Meta-disclaimer: Any society that needs disclaimers has too many lawyers.