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 thewidth
andheight
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) { <Movep1
andp2
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 bitmap
s to rectangle
s 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;
Definesbitmap
,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 pointp1
outside ofmap1
?> <Is origin ofrect2
outside ofmap2
?> <Is opposite corner ofrect2
outside ofmap2
?> <Is opposite corner inmap1
outside?>
<Find thewidth
andheight
of the rectangle in bits>= (<-U) width = rect2.bottomRight.x - rect2.topLeft.x; height = rect2.bottomRight.y - rect2.topLeft.y;
Definesheight
,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;
DefinesbitPointer
(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.
<Movep1
andp2
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 pointp1
outside ofmap1
?>= (<-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; }
<Is origin ofrect2
outside ofmap2
?>= (<-U)
p2
, to the first bit of the destination>: U1, D2
p1
, to the first bit of the source>: U1, D2
width
and height
of the rectangle in bits>: U1, D2
map1
outside?>: U1
rect2
outside of map2
?>: U1
rect2
outside of map2
?>: U1, D2
p1
outside of map1
?>: U1, D2
p1
and p2
to the lower right source and destination word>: U1, D2