#include "blitter.h"
typedef struct TBlitter_
{
int width;
int height;
int xread;
int yread;
int xwrite;
int ywrite;
int right_clip;
char* read;
char* write;
int read_line;
int write_line;
TT_Raster_Map source;
TT_Raster_Map target;
int source_depth;
int target_depth;
} TBlitter;
static
int compute_clips( TBlitter* blit,
int x_offset,
int y_offset )
{
int xmin, ymin, xmax, ymax, width, height, target_width;
width = blit->source.width;
height = blit->source.rows;
switch ( blit->source_depth )
{
case 1:
width = (width + 7) & -8;
break;
case 4:
width = (width + 1) & -2;
break;
}
xmin = x_offset;
ymin = y_offset;
xmax = xmin + width-1;
ymax = ymin + height-1;
if ( width == 0 || height == 0 ||
xmax < 0 || xmin >= blit->target.width ||
ymax < 0 || ymin >= blit->target.rows )
return 1;
blit->yread = 0;
if ( ymin < 0 )
{
blit->yread -= ymin;
height += ymin;
blit->ywrite = 0;
}
else
blit->ywrite = ymin;
if ( ymax >= blit->target.rows )
height -= ymax - blit->target.rows + 1;
blit->xread = 0;
if ( xmin < 0 )
{
blit->xread -= xmin;
width += xmin;
blit->xwrite = 0;
}
else
blit->xwrite = xmin;
target_width = blit->target.width;
switch ( blit->target_depth )
{
case 1:
target_width = (target_width + 7) & -8;
break;
case 4:
target_width = (target_width + 1) & -2;
break;
}
blit->right_clip = xmax - target_width + 1;
if ( blit->right_clip > 0 )
width -= blit->right_clip;
else
blit->right_clip = 0;
blit->width = width;
blit->height = height;
blit->read = (char*)blit->source.bitmap;
blit->write = (char*)blit->target.bitmap;
if ( blit->source.flow == TT_Flow_Up )
{
blit->read_line = -blit->source.cols;
blit->read += (blit->source.rows-1) * blit->source.cols;
}
else
blit->read_line = blit->source.cols;
if ( blit->target.flow == TT_Flow_Up )
{
blit->write_line = -blit->target.cols;
blit->write += (blit->target.rows-1) * blit->target.cols;
}
else
blit->write_line = blit->target.cols;
blit->read += blit->yread * blit->read_line;
blit->write += blit->ywrite * blit->write_line;
return 0;
}
static
void blit_bitmap_to_bitmap( TBlitter* blit )
{
int shift, left_clip, x, y;
unsigned char* read;
unsigned char* write;
left_clip = ( blit->xread > 0 );
shift = ( blit->xwrite - blit->xread ) & 7;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + (blit->xwrite >> 3);
if ( shift == 0 )
{
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
x = blit->width;
do
{
*_write++ |= *_read++;
x -= 8;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
else
{
int first, last, count;
first = blit->xwrite >> 3;
last = (blit->xwrite + blit->width-1) >> 3;
count = last - first;
if ( blit->right_clip )
count++;
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned char old;
int shift2 = (8-shift);
if ( left_clip )
old = (*_read++) << shift2;
else
old = 0;
x = count;
while ( x > 0 )
{
unsigned char val;
val = *_read++;
*_write++ |= ( (val >> shift) | old );
old = val << shift2;
x--;
}
if ( !blit->right_clip )
*_write |= old;
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
}
static
void blit_bitmap_to_pixmap8( TBlitter* blit,
unsigned char color )
{
int x, y;
unsigned int left_mask;
unsigned char* read;
unsigned char* write;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + blit->xwrite;
left_mask = 0x80 >> (blit->xread & 7);
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned int mask = left_mask;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
*_write = (unsigned char)color;
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write++;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
static
void blit_bitmap_to_pixmap4( TBlitter* blit,
unsigned char color )
{
int x, y, phase;
unsigned int left_mask;
unsigned char* read;
unsigned char* write;
color = color & 15;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned char*)blit->write + (blit->xwrite >> 1);
left_mask = 0x80 >> (blit->xread & 7);
phase = blit->xwrite & 1;
y = blit->height;
do
{
unsigned char* _read = read;
unsigned char* _write = write;
unsigned int mask = left_mask;
int _phase = phase;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
{
if ( _phase )
*_write = (*_write & 0xF0) | color;
else
*_write = (*_write & 0x0F) | (color << 4);
}
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write += _phase;
_phase ^= 1;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
static
void blit_bitmap_to_pixmap16( TBlitter* blit,
unsigned short color )
{
int x, y;
unsigned int left_mask;
unsigned char* read;
unsigned short* write;
read = (unsigned char*)blit->read + (blit->xread >> 3);
write = (unsigned short*)(blit->write + blit->xwrite*2);
left_mask = 0x80 >> (blit->xread & 7);
y = blit->height;
do
{
unsigned char* _read = read;
unsigned short* _write = write;
unsigned int mask = left_mask;
unsigned int val = 0;
x = blit->width;
do
{
if ( mask == 0x80 )
val = *_read++;
if ( val & mask )
*_write = color;
mask >>= 1;
if ( mask == 0 )
mask = 0x80;
_write++;
x--;
} while ( x > 0 );
read += blit->read_line;
write += blit->write_line;
y--;
} while ( y > 0 );
}
extern
int Blit_Bitmap( TT_Raster_Map* target,
TT_Raster_Map* source,
int target_depth,
int x_offset,
int y_offset,
int color )
{
TBlitter blit;
if ( !target || !source )
return -1;
blit.source = *source;
blit.target = *target;
blit.source_depth = 1;
blit.target_depth = target_depth;
if ( compute_clips( &blit, x_offset, y_offset ) )
return 0;
switch ( target_depth )
{
case 1:
blit_bitmap_to_bitmap( &blit );
break;
case 4:
blit_bitmap_to_pixmap4( &blit, (unsigned char)color );
break;
case 8:
blit_bitmap_to_pixmap8( &blit, (unsigned char)color );
break;
case 16:
blit_bitmap_to_pixmap16( &blit, (unsigned short)color );
break;
default:
return -2;
}
return 0;
}