Here is how both sequence and bitmap headers are represented internally:
typedef unsigned char byte_t;
struct header_t
{
byte_t h_bits; // bits per pixel (currently 1 or 2)
byte_t h_count; // number of bitmaps in the file (1..255)
byte_t h_width; // original width
byte_t h_height; // original height
bitmap_t h_body[ 1 ]; // bitmaps
};
struct bitmap_t
{
byte_t b_xorg; // x-origin, pels
byte_t b_yorg; // y-origin, pels
byte_t b_width; // raster width, pels
byte_t b_height; // raster height, pels
byte_t b_raster[ 1 ]; // scanlines
};
And here is how rasters are stored (i.e. how b_raster[] is formed; process of
loading must be just the opposite). Please note that (x1, y1, x2, y2) is a
non-transparent rectangle of original frame (0, 0, header_t::h_width,
header_t::h_height).
x1 = bitmap_t::b_xorg;
y1 = bitmap_t::b_yorg;
x2 = x1 + bitmap_t::b_width - 1;
y2 = y1 + bitmap_t::b_height - 1;
total_bits = header_t::h_bits;
for( y = y1; y <= y2; y ++ )
{
bit = 7;
byte = 0;
for( x = x1; x <= x2; x ++ )
{
pixel = "pixel at x, y"
byte |= total_bits == 1 ? ( pixel == P_BLACK ) << bit:
(( pixel ^ 3 ) & 3 ) << bit - 1;
bit -= total_bits;
if( bit < 0 ) putc( byte, file ), bit = 7, byte = 0;
}
if( bit != 7 ) putc( byte, file );
}
At last, here is how rasters are loaded by emulator. Although it addresses
loading, this example is probably less useful than previous, because code in
emulator converts 1- and 2-bit pixels into bytes, on the fly, for more simple
and effective processing. Cybiko applications are not supposed to behave this
way, i.e. they must not expand rasters.
x1 = bitmap_t::b_xorg;
y1 = bitmap_t::b_yorg;
x2 = x1 + bitmap_t::b_width - 1;
y2 = y1 + bitmap_t::b_height - 1;
total_bits = header_t::h_bits;
bit = 0 // current bit, 1..8;
byte = 0 // cyrrent packet;
int get_bit( FILE* file, int& bit, int& byte )
{
if( bit == 0 ) byte = (byte_t) getc( file ), bit = 8;
if( byte == EOF ) die( "get_bit: premature end-of-file" );
return ( byte & 1 << -- bit ) != 0;
}
for( y = y1; y <= y1; y ++ )
{
for( x = x1; x <= x2; x ++ )
{
pixel = 0;
for( b = 0; b < bits; b ++ )
{
pixel <<= 1;
pixel += get_bit( file, bit, byte );
}
switch( pixel )
{
case 0: pixel = clr_white; break;
case 1: pixel = bits == 1 ? clr_black: clr_ltgray; break;
case 2: pixel = clr_dkgray; break;
default: pixel = clr_black;
}
"pixel at x, y" = pixel;
}
bit = 0; // abandon trailing bits ( end of scanline )
}
|