Introduction to blits

The Blit Format

Our blits have evolved over time. Originally they were just ripped from screen memory and treated as one long stream of runs of pixels. There was no width or height information stored, or how many runs were on a line. However, due to clipping needs we've made a few changes. Now the format is as follows (given that the original image is defined by (x1,y1),(x2,y2) ):
Leftmost_X_coord:word [relative to (x1,y1)]
Topmost_Y_coord:word [relative to (x1,y1)]
Rightmost_X_coord:word [relative to (x1,y1)]
Bottommost_Y_coord:word [relative to (x1,y1)]
OffsetTable:array[0..(y2-y1)] of word 
For y1 to y2 
  if LineCount<>0 then
    for 0 to LineCount-1 
      rundata:array[0..PixelCount-1] of byte
    end for
  end if
end for

That is the Blit Format Version 2.0. Unfortunately, due to the OffsetTable being an array of words (16-bit values), the blit is limited to 64K. BFV2.1 may use longints. If a blit exceeds 64K then another method may be in order for drawing such a large transparent sprite.

The first 4 words contain information about the portion of the blit that actually contains data. For example:
Very important image
The white rectangles in the above image represent the coordinates of the original bitmap. The reason to make the bounding rectangle larger than the image is to allow for easy synchronization of frames. All that is required to animate and move frames is to keep track of the upper left coordinate. The actual image data is composed of the coordinates (x1+LeftMost_X_Coord,y1+TopMost_Y_Coord),(x1+RightMost_X_Coord,y1+BottomMost_Y_Coord). The space outside those coordinates is devoid of image data. This bounding rectangle helps the blit routine establish if part or all of the blit is off the screen regardless of where the upper left corner is. The first 4 words (8 bytes) of the blit are not considered a part of the blit data. This is important due to how the OffsetTable array works.

The OffsetTable array is a table of offsets (duh?) to the beginning of each scan line in the blit. This table is present to help with clipping on the top and bottom edges of the screen (or the buffer you are blitting to). The following code presumes that the blit is contained at a 32-bit [Pascal style] pointer called BlitPtr:
	lds	si,BlitPtr  ; {Load the pointer into DS:SI}
	add	si,8	    ; {go past the bounding coords}
	mov	dx,ds:[si]  ; {Get address of the first line}
	add	si,dx       ; {Go past table to the start of the first line}
	shr	dx,1	    ; {Divide DX by 2 which is the TotalYCount}
;{DS:SI now points to right after the OffsetTable; DX is now the number}
;{of scanlines in blit}

If DX=0 after the shr dx,1 then there are no lines in the blit and the blit routine should exit. The first word ends up being how big the table is multipled by 2 (since words are two bytes). So, by taking this number and dividing it by two you will get how many scanlines the blit takes up.

The BlitSize() routine

When working with bitmaps and using getimage() or putimage() style routines, you could simply compute how big the image was with the following routine:
function ImageSize(x1, y1, x2, y2: Integer): Word;
(Note: ImageSize() from the BGI works in a slightly different way producing results that are in 8 or 16 byte chunks).

Blits are variable in size, so a simple function cannot compute how much space is needed for allocation before hand. A quick pass through is needed to compute the space. Because blits are usually pre-generated, the speed of the BlitSize() and GetBlit() routines shouldn't be an issue.
function BlitSize(const x1,y1,x2,y2:word):word;
var x,y,tmploc:word;
 for y:=y1 to y2 do
   inc(tmploc);            {Save room for linecount}
   inzeros:=(getpixel(x,y)=0);  {Should we start in zeros?}
   while x<=x2 do           {Continue until we are done with the line}
    case inzeros of
           zerocount:=0;   {How many zeros?}
           while (x<=x2) and (getpixel(x,y)=0) do
           inzeros:=FALSE  {we are no longer in zeros}
            inc(tmploc,4); {zerocount (offset):word; xlcount:word}
            until (x>=x2) or (getpixel(x,y)=0);
Previous pageUp one level