/****************************************************************************/ /* */ /* The FreeType project -- a free and portable quality TrueType renderer. */ /* */ /* Copyright 1996-1999 by */ /* D. Turner, R.Wilhelm, and W. Lemberg */ /* */ /* blitter.c: Support for blitting of bitmaps with various depth. */ /* */ /****************************************************************************/ #include "blitter.h" typedef struct TBlitter_ { int width; /* width in pixels of the written area */ int height; /* height in pixels of the written area */ int xread; /* x position of start point in read area */ int yread; /* y position of start point in read area */ int xwrite; /* x position of start point in write area */ int ywrite; /* y position of start point in write area */ int right_clip; /* amount of right clip */ char* read; /* top left corner of source map */ char* write; /* top left corner of target map */ int read_line; /* byte increment to go down one row in read area */ int write_line; /* byte increment to go down one row in write area */ 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; /* perform clipping and setup variables */ 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; /* clip if necessary */ if ( width == 0 || height == 0 || xmax < 0 || xmin >= blit->target.width || ymax < 0 || ymin >= blit->target.rows ) return 1; /* set up clipping and cursors */ 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; /* set read and write to the top-left corner of the the read */ /* and write area before clipping. */ 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; /* now go to the start line. Note that we do not move the */ /* x position yet, as this is dependent on the pixel format */ blit->read += blit->yread * blit->read_line; blit->write += blit->ywrite * blit->write_line; return 0; } /**************************************************************************/ /* */ /* blit_bitmap_to_bitmap */ /* */ /**************************************************************************/ 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 ); } } /**************************************************************************/ /* */ /* blit_bitmap_to_pixmap8 */ /* */ /**************************************************************************/ 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 ); } /**************************************************************************/ /* */ /* blit_bitmap_to_pixmap4 */ /* */ /**************************************************************************/ 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); /* now begin blit */ 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 ); } /**************************************************************************/ /* */ /* blit_bitmap_to_pixmap16 */ /* */ /**************************************************************************/ 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 ); } /* */ /* Blit_Bitmap */ /* */ /* */ /* blit a source bitmap to a target bitmap or pixmap */ /* */ /* */ /* target :: target bitmap or pixmap */ /* source :: source bitmap (depth must be 1) */ /* target_depth :: pixel bit depth of target map */ /* x_offset :: horizontal offset of source in target */ /* y_offset :: vertical offset of source in target */ /* color :: color to use when blitting to color pixmap */ /* */ /* */ /* error code. 0 means success */ /* */ /* */ /* an error occurs when the target bit depth isn't supported, or */ /* if the source's bit depth isn't 1. */ /* */ /* the offsets are relative to the top-left corner of the target */ /* map. Positive y are downwards. */ /* */ 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; /* set up blitter and compute clipping. Return immediately if needed */ if ( compute_clips( &blit, x_offset, y_offset ) ) return 0; /* now perform the blit */ 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; } /* End */