The following pseudocode for bitblt is derived from Foley and Van Dam [cite fvfh:95].

The file is written in a C style pseudocode and consists of several type definitions, some auxiliary functions and the algorithm for the bit block-transfer.

<*>=
  <Type definitions>
  <Auxiliary functions>
  <BitBlt Algorithm>

The bitBlt operation is decribed by the following chunks of code.

<BitBlt Algorithm>= (<-U)
  void bitblt(
    bitmap map1,      /* the source               */
    point point1,     /* corner of region to copy */
    texture tex,      /* a word x word array      */
    bitmap map2,      /* the destination          */
    rectangle rect2   /* target in destination    */
    writeMode mode) {

  <Clip the rectangles to the source and destination bitmaps>
  <Find the width and height of the rectangle in bits>
  if ((width < 0) || (height < 0)) {
     return;
  }
  <Compute a pointer, p1, to the first bit of the source>
  <Compute a pointer, p2, to the first bit of the destination>
  if (p1 < p2) {
     <Move p1 and p2 to the lower right source and destination word>
     <Copy rows of the source to the destination, bottom to top>
  }
  else {
     <Copy rows of the source to the destination, top to bottom>
  }
}

To clip the bitmaps to rectangles we will need to have an understanding of these types.

<Type definitions>= (<-U) [D->]
  typedef struct {
    int x, y;
  } point;

  typedef struct {
    point topLeft, bottomRight;
  } rectangle;

  typedef struct {
    char *base;
    int width;
    rectangle rect;
  } bitmap;


Defines bitmap, point, rectangle (links are to index).

The clipping process guarantees that the region that is mapped lies within the source and will lie within the destination. For example, the rectangle to be copied could be too large to fit in the source or destination. We'll describe the basic cases but leave the expansion of the code until later.

<Clip the rectangles to the source and destination bitmaps>= (<-U)
 <Is point p1 outside of map1?>
 <Is origin of rect2 outside of map2?>
 <Is opposite corner of rect2 outside of map2?>
 <Is opposite corner in map1 outside?>


<Find the width and height of the rectangle in bits>= (<-U)
  width  = rect2.bottomRight.x - rect2.topLeft.x;
  height = rect2.bottomRight.y - rect2.topLeft.y;


Defines height, width (links are to index).

We want to be able to address individual bits within the map.

<Type definitions>+= (<-U) [<-D]
  typedef struct {
    char *wordptr;
    int bit;
  } bitPointer;

Defines bitPointer (links are to index).

We'll define p1 to be a bitPointer to the start of the source bitmap (map1). The remainder of the topLeft x coordinate when divided by 32 identifies the first bit in the map (word sizes are assumed to be 32 bits).

The start of the portion of the bitmap we wish to copy may be a few bit farther in. We'll delay figuring out exactly where this is and use a function IncrementPointer() to calculate it. However, it is easy to see that the distance between two points (x0, y0) and (x1, y1) in an array x1-x0+width*(y1-y0).

<Compute a pointer, p1, to the first bit of the source>= (<-U)
  p1.wordptr = map1.base;
  p1.bit = map1.rect.topLeft.x % 32;
  IncrementPointer(p1, point1.x - map1.rect.topLeft.x
        map1.width*(point1.topLeft.y - map1.rect.topLeft.y));

Bit pointer p2 points to the first word and bit of region to copy into in the destination map2.

<Compute a pointer, p2, to the first bit of the destination>= (<-U)
  p2.wordptr = map2.base;
  p2.bit = map2.rect.topLeft.x % 32;
  IncrementPointer(p2, rect2.topLeft.x-map2.rect.topLeft.x+
        map2.width*(rect2.topLeft.y - map2.rect.topLeft.y));

When p1 < p2 a situation shown in the drawing below can occur. Copying the first few rows of map1 into map2 will destroy a region of map1. We can avoid this by copying map1 into map2 from the bottom to the top in a right to left fashion.

[picture]

The first thing to do is to move the two pointers to the last word (in their maps) of the rectangle to be copied. They currently point to the first word (in their maps) of the rectangle.

<Move p1 and p2 to the lower right source and destination word>= (<-U)
  IncrementPointer(p1, height*map1.width+width);
  IncrementPointer(p2, height*map2.width+width);

While there are still rows to be transferred, transfer a row from map1 to map2 and decrement the pointers to the start of the next row.

<Copy rows of the source to the destination, bottom to top>= (<-U)
  while (height-- > 0) {
    DecrementPointer(p1, map1.width);     
    DecrementPointer(p2, map2.width);     
    tempX = point1.y % 32;
    tempY = point1.y % 32;
    rowBltNegative(p1, p2, width, bitRotate(tex[tempY], tempX), mode);
  }

While there are still rows to be transferred, transfer a row from map1 to map2 and increment the pointers to the start of the next row.

<Copy rows of the source to the destination, top to bottom>= (<-U)
  while (height-- > 0) {
    rowBltPositive(p1, p2, width, bitRotate(tex[tempY], tempX), mode);
    IncrementPointer(p1, map1.width);
    IncrementPointer(p2, map2.width);
  }

To move n bits in the map, one must determine the location of the new word that will be pointed to and the bit within that word. Since words are 32 bits long, the next word will be at least n/32 words farther along (for example if n=134 then we must move at least 4 words). We must also set the bit within the word to the remainder n % 32 plus what ever offset there is in the current word. In the case of overflow (beyond 32 bits) the word pointer must be incremented (by 1) and the bit pointer decremented (by 32). Decrementing a bit pointer is similar

<Auxiliary functions>= (<-U) [D->]
  IncrementPointer(bitptr ptr, int n) {
    ptr.wordptr += n/32;
    ptr.bit += n % 32;
    if (ptr.bit >= 32) {
        ++(ptr.wordptr);
        ptr.bit -= 32;
    }
  }

  DecrementPointer(bitptr ptr, int n) {
    ptr.wordptr -= n/32;
    ptr.bit -= n % 32;
    if (ptr.bit < 0) {
        --(ptr.wordptr);
        ptr.bit += 32;
    }

  }

<Auxiliary functions>+= (<-U) [<-D]
  rowBltPositive(
     bitptr p1, bitptr p2, /* source and destination pointer */
     int n,                /* number of bits to copy         */
     char texword,         /* The word in texture map to use */
     writeMode mode;       /* raster operation mode          */
  {
     while (n-- > 0) {
       if (bitIsSet(texword, 32)) {
          MoveBit(p1, p2, mode);
       }
       IncrementPointer(p1, 1);
       IncrementPointer(p2, 1);
       RotateLeft(texword);
    }
  }

Now let's fill in the details of the clipping code.

<Is point p1 outside of map1?>= (<-U)
  if (p1.topLeft.x < map1.topLeft.x) {
      rect2.topLeft.x = map1.topLeft.x - p1.topLeft.x;
      p1.topLeft.x = map1.topLeft.x;
  }
  if (p1.topLeft.y < map1.topLeft.y) {
      rect2.topLeft.y = map1.topLeft.y - p1.topLeft.y;
      p1.topLeft.y = map1.topLeft.y;
  }
  if (p1.bottomRight.x > map1.bottomRight.x) {
      rect2.bottomRight.x = map1.bottomRight.x - p1.bottomRight.x;
      p1.bottomRight.x = map1.bottomRight.x;
  }
  if (p1.bottomRight.y > map1.bottomRight.y) {
      rect2.bottomRight.y = map1.bottomRight.y - p1.bottomRight.y;
      p1.bottomRight.y = map1.bottomRight.y;
  }

Another test

<Is origin of rect2 outside of map2?>= (<-U)