/****************************************************************************/ /* */ /* The FreeType project -- a free and portable quality TrueType renderer. */ /* */ /* Copyright 1996-1999, 2000, 2001, 2002 by */ /* D. Turner, R.Wilhelm, and W. Lemberg */ /* */ /* grblit.c: Support for blitting of bitmaps with various depth. */ /* */ /****************************************************************************/ #include "grblit.h" #include "grobjs.h" #include #define GRAY8 static int compute_clips( grBlitter* 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.mode ) { case gr_pixel_mode_mono: width = (width + 7) & -8; break; case gr_pixel_mode_pal4: width = (width + 1) & -2; break; case gr_pixel_mode_lcd: case gr_pixel_mode_lcd2: width /= 3; break; case gr_pixel_mode_lcdv: case gr_pixel_mode_lcdv2: height /= 3; break; default: ; } 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.mode ) { case gr_pixel_mode_mono: target_width = (target_width + 7) & -8; break; case gr_pixel_mode_pal4: target_width = (target_width + 1) & -2; break; default: ; } 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 read */ /* and write areas before clipping. */ blit->read = blit->source.buffer; blit->write = blit->target.buffer; blit->read_line = blit->source.pitch; blit->write_line = blit->target.pitch; if ( blit->read_line < 0 ) blit->read -= (blit->source.rows-1) * blit->read_line; if ( blit->write_line < 0 ) blit->write -= (blit->target.rows-1) * blit->write_line; /* 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_mono_to_mono */ /* */ /**************************************************************************/ static void blit_mono_to_mono( grBlitter* blit, grColor color ) { int shift, left_clip, x, y; byte* read; byte* write; (void)color; /* unused argument */ left_clip = ( blit->xread > 0 ); shift = ( blit->xwrite - blit->xread ) & 7; read = blit->read + (blit->xread >> 3); write = blit->write + (blit->xwrite >> 3); if ( shift == 0 ) { y = blit->height; do { byte* _read = read; byte* _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 int 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++ |= (unsigned char)( (val >> shift) | old ); old = val << shift2; x--; } if ( !blit->right_clip ) *_write |= (unsigned char)old; read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } } /**************************************************************************/ /* */ /* blit_mono_to_pal8 */ /* */ /**************************************************************************/ static void blit_mono_to_pal8( grBlitter* blit, grColor color ) { int x, y, shift; unsigned char* read; unsigned char* write; read = blit->read + (blit->xread >> 3); write = blit->write + blit->xwrite; shift = blit->xread & 7; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; unsigned long val = (*_read++ | 0x100) << shift; x = blit->width; do { if (val & 0x10000) val = *_read++ | 0x100; if ( val & 0x80 ) *_write = (unsigned char)color.value; val <<= 1; _write++; } while ( --x > 0 ); read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } /**************************************************************************/ /* */ /* blit_mono_to_pal4 */ /* */ /**************************************************************************/ static void blit_mono_to_pal4( grBlitter* blit, grColor color ) { int x, y, phase,shift; unsigned char* read; unsigned char* write; unsigned int col; col = color.value & 15; read = blit->read + (blit->xread >> 3); write = blit->write + (blit->xwrite >> 1); /* now begin blit */ shift = blit->xread & 7; phase = blit->xwrite & 1; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int _phase = phase; unsigned long val = (*_read++ | 0x100) << shift; x = blit->width; do { if (val & 0x10000) val = *_read++ | 0x100; if ( val & 0x80 ) { if ( _phase ) *_write = (unsigned char)((*_write & 0xF0) | col); else *_write = (unsigned char)((*_write & 0x0F) | (col << 4)); } val <<= 1; _write += _phase; _phase ^= 1; x--; } while ( x > 0 ); read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } /**************************************************************************/ /* */ /* blit_mono_to_rgb16 */ /* */ /**************************************************************************/ static void blit_mono_to_rgb16( grBlitter* blit, grColor color ) { int x, y,shift; unsigned char* read; unsigned char* write; read = blit->read + (blit->xread >> 3); write = blit->write + blit->xwrite*2; shift = blit->xread & 7; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; unsigned long val = (*_read++ | 0x100) << shift; x = blit->width; do { if (val & 0x10000) val = *_read++ | 0x100; if ( val & 0x80 ) *(short*)_write = (short)color.value; val <<= 1; _write +=2; x--; } while ( x > 0 ); read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } /**************************************************************************/ /* */ /* blit_mono_to_rgb24 */ /* */ /**************************************************************************/ static void blit_mono_to_rgb24( grBlitter* blit, grColor color ) { int x, y, shift; unsigned char* read; unsigned char* write; read = blit->read + (blit->xread >> 3); write = blit->write + blit->xwrite*3; shift = blit->xread & 7; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; unsigned long val = (*_read++ | 0x100) << shift; x = blit->width; do { if (val & 0x10000) val = *_read++ | 0x100; if ( val & 0x80 ) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } val <<= 1; _write += 3; x--; } while ( x > 0 ); read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } /**************************************************************************/ /* */ /* blit_mono_to_rgb32 */ /* */ /**************************************************************************/ static void blit_mono_to_rgb32( grBlitter* blit, grColor color ) { int x, y,shift; unsigned char* read; unsigned char* write; read = blit->read + ( blit->xread >> 3 ); write = blit->write + blit->xwrite*4; shift = blit->xread & 7; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; unsigned long val = ( *_read++ | 0x100L ) << shift; x = blit->width; do { if ( val & 0x10000 ) val = *_read++ | 0x100L; if ( val & 0x80 ) { /* this could be greatly optimized as */ /* */ /* *(long*)_write = color.value */ /* */ /* but it wouldn't work on 64-bits systems... stupid C types! */ _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; _write[3] = color.chroma[3]; } val <<= 1; _write += 4; x--; } while ( x > 0 ); read += blit->read_line; write += blit->write_line; y--; } while ( y > 0 ); } static const grBlitterFunc gr_mono_blitters[gr_pixel_mode_max] = { 0, blit_mono_to_mono, blit_mono_to_pal4, blit_mono_to_pal8, blit_mono_to_pal8, blit_mono_to_rgb16, blit_mono_to_rgb16, blit_mono_to_rgb24, blit_mono_to_rgb32 }; /*******************************************************************/ /* */ /* Saturation tables */ /* */ /*******************************************************************/ typedef struct grSaturation_ { int count; const byte* table; } grSaturation; static const byte gr_saturation_5[8] = { 0, 1, 2, 3, 4, 4, 4, 4 }; static const byte gr_saturation_17[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }; static grSaturation gr_saturations[ GR_MAX_SATURATIONS ] = { { 5, gr_saturation_5 }, { 17, gr_saturation_17 } }; static int gr_num_saturations = 2; static grSaturation* gr_last_saturation = gr_saturations; extern const byte* grGetSaturation( int num_grays ) { /* first of all, scan the current saturations table */ grSaturation* sat = gr_saturations; grSaturation* limit = sat + gr_num_saturations; if ( num_grays < 2 ) { grError = gr_err_bad_argument; return 0; } for ( ; sat < limit; sat++ ) { if ( sat->count == num_grays ) { gr_last_saturation = sat; return sat->table; } } /* not found, simply create a new entry if there is room */ if (gr_num_saturations < GR_MAX_SATURATIONS) { int i; const byte* table; table = (const byte*)grAlloc( (3*num_grays-1)*sizeof(byte) ); if (!table) return 0; sat->count = num_grays; sat->table = table; for ( i = 0; i < num_grays; i++, table++ ) *(unsigned char*)table = (unsigned char)i; for ( i = 2*num_grays-1; i > 0; i--, table++ ) *(unsigned char*)table = (unsigned char)(num_grays-1); gr_num_saturations++; gr_last_saturation = sat; return sat->table; } grError = gr_err_saturation_overflow; return 0; } /*******************************************************************/ /* */ /* conversion tables */ /* */ /*******************************************************************/ typedef struct grConversion_ { int target_grays; int source_grays; const byte* table; } grConversion; static const byte gr_gray5_to_gray17[5] = { 0, 4, 8, 12, 16 }; static const byte gr_gray5_to_gray128[5] = { 0, 32, 64, 96, 127 }; static const unsigned char gr_gray17_to_gray128[17] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 127 }; static grConversion gr_conversions[ GR_MAX_CONVERSIONS ] = { { 17, 5, gr_gray5_to_gray17 }, { 128, 5, gr_gray5_to_gray128 }, { 128, 17, gr_gray17_to_gray128 } }; static int gr_num_conversions = 3; static grConversion* gr_last_conversion = gr_conversions; extern const byte* grGetConversion( int target_grays, int source_grays ) { grConversion* conv = gr_conversions; grConversion* limit = conv + gr_num_conversions; if ( target_grays < 2 || source_grays < 2 ) { grError = gr_err_bad_argument; return 0; } /* otherwise, scan table */ for ( ; conv < limit; conv++ ) { if ( conv->target_grays == target_grays && conv->source_grays == source_grays ) { gr_last_conversion = conv; return conv->table; } } /* not found, add a new conversion to the table */ if (gr_num_conversions < GR_MAX_CONVERSIONS) { const byte* table; int n; table = (const byte*)grAlloc( source_grays*sizeof(byte) ); if (!table) return 0; conv->target_grays = target_grays; conv->source_grays = source_grays; conv->table = table; for ( n = 0; n < source_grays; n++ ) ((unsigned char*)table)[n] = (unsigned char)(n*(target_grays-1) / (source_grays-1)); gr_num_conversions++; gr_last_conversion = conv; return table; } grError = gr_err_conversion_overflow; return 0; } /**************************************************************************/ /* */ /* blit_gray_to_gray */ /* */ /**************************************************************************/ static void blit_gray_to_gray( grBlitter* blit, const byte* saturation, const byte* conversion ) { int y; unsigned char* read; unsigned char* write; unsigned char max1; unsigned char max2; max1 = (unsigned char)(blit->source.grays-1); max2 = (unsigned char)(blit->target.grays-1); read = blit->read + blit->xread; write = blit->write + blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { #ifdef GR_CONFIG_GRAY_SKIP_WHITE unsigned char val = *_read; if (val) { if (val == max) *_write = max2; else *_write = saturation[ (int)*_write + conversion[ *_read ] ]; } #else *_write = saturation[ (int)*_write + conversion[ *_read ] ]; #endif _write++; _read++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } /**************************************************************************/ /* */ /* blit_gray_to_gray_simple */ /* */ /**************************************************************************/ static void blit_gray_to_gray_simple( grBlitter* blit, const byte* saturation ) { int y; unsigned char* read; unsigned char* write; unsigned char max; max = (unsigned char)(blit->source.grays-1); read = blit->read + blit->xread; write = blit->write + blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { #ifdef GR_CONFIG_GRAY_SKIP_WHITE unsigned char val = *_read; if (val) { if (val == max) *_write = val; else *_write = saturation[ (int)*_write + *_read ]; } #else *_write = saturation[ (int)*_write + *_read ]; #endif _write++; _read++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #define compose_pixel_full( a, b, n0, n1, n2, max ) \ { \ int d, half = max >> 1; \ \ \ d = (int)b.chroma[0] - a.chroma[0]; \ a.chroma[0] += (unsigned char)((n0*d + half)/max); \ \ d = (int)b.chroma[1] - a.chroma[1]; \ a.chroma[1] += (unsigned char)((n1*d + half)/max); \ \ d = (int)b.chroma[2] - a.chroma[2]; \ a.chroma[2] += (unsigned char)((n2*d + half)/max); \ } #define compose_pixel( a, b, n, max ) \ compose_pixel_full( a, b, n, n, n, max ) #define extract555( pixel, color ) \ color.chroma[0] = (unsigned char)((pixel >> 10) & 0x1F); \ color.chroma[1] = (unsigned char)((pixel >> 5) & 0x1F); \ color.chroma[2] = (unsigned char)((pixel ) & 0x1F); #define extract565( pixel, color ) \ color.chroma[0] = (unsigned char)((pixel >> 11) & 0x1F); \ color.chroma[1] = (unsigned char)((pixel >> 5) & 0x3F); \ color.chroma[2] = (unsigned char)((pixel ) & 0x1F); #define inject555( color ) \ ( ( (unsigned short)color.chroma[0] << 10 ) | \ ( (unsigned short)color.chroma[1] << 5 ) | \ color.chroma[2] ) #define inject565( color ) \ ( ( (unsigned short)color.chroma[0] << 11 ) | \ ( (unsigned short)color.chroma[1] << 5 ) | \ color.chroma[2] ) /**************************************************************************/ /* */ /* blit_gray_to_555 */ /* */ /**************************************************************************/ #ifdef GRAY8 static void blit_gray8_to_555( grBlitter* blit, grColor color ) { int y; int sr = (color.chroma[0] << 8) & 0x7C00; int sg = (color.chroma[1] << 2) & 0x03E0; int sb = (color.chroma[2] ) & 0x001F; unsigned char* read; unsigned char* write; long color2; read = blit->read + blit->xread; write = blit->write + 2*blit->xwrite; color2 = color.value; extract565( color2, color ); y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { unsigned short* pixel = (unsigned short*)_write; if (val >= 254 ) { pixel[0] = (short)color2; } else if ( val >= 2 ) { /* compose gray value */ int pix = (int)*pixel; int dr = pix & 0x7C00; int dg = pix & 0x03E0; int db = pix & 0x001F; dr = pix & 0x7C00; dr += ((sr-dr)*val) >> 8; dr &= 0xF800; dg = pix & 0x03E0; dg += ((sg-dg)*val) >> 8; dg &= 0x7E0; db = pix & 0x001F; db += ((sb-db)*val) >> 8; db += 0x001F; *pixel = (short)( dr | dg | db ); } } _write +=2; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #endif /* GRAY8 */ static void blit_gray_to_555( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; long color2; read = blit->read + blit->xread; write = blit->write + 2*blit->xwrite; /* convert color to R:G:B triplet */ color2 = color.value; extract555( color2, color ); y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { unsigned short* pixel = (unsigned short*)_write; if (val == max) { pixel[0] = (short)color2; } else { /* compose gray value */ unsigned short pix16 = *pixel; grColor pix; extract555( pix16, pix ); compose_pixel( pix, color, val, max ); *pixel = (unsigned short)(inject555(pix)); } } _write += 2; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } /**************************************************************************/ /* */ /* blit_gray_to_565 */ /* */ /**************************************************************************/ #ifdef GRAY8 static void blit_gray8_to_565( grBlitter* blit, grColor color ) { int y; int sr = (color.chroma[0] << 8) & 0xF800; int sg = (color.chroma[1] << 2) & 0x07E0; int sb = (color.chroma[2] ) & 0x001F; unsigned char* read; unsigned char* write; long color2; read = blit->read + blit->xread; write = blit->write + 2*blit->xwrite; color2 = color.value; extract565( color2, color ); y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { unsigned short* pixel = (unsigned short*)_write; if (val >= 254 ) { pixel[0] = (short)color2; } else if ( val >= 2 ) { /* compose gray value */ int pix = (int)*pixel; int dr = pix & 0xF800; int dg = pix & 0x07E0; int db = pix & 0x001F; dr = pix & 0xF800; dr += ((sr-dr)*val) >> 8; dr &= 0xF800; dg = pix & 0x07E0; dg += ((sg-dg)*val) >> 8; dg &= 0x7E0; db = pix & 0x001F; db += ((sb-db)*val) >> 8; db += 0x001F; *pixel = (short)( dr | dg | db ); } } _write +=2; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #endif static void blit_gray_to_565( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; long color2; read = blit->read + blit->xread; write = blit->write + 2*blit->xwrite; color2 = color.value; extract565( color2, color ); y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { unsigned short* pixel = (unsigned short*)_write; if (val == max) { pixel[0] = (short)color2; } else { /* compose gray value */ unsigned short pix16 = *pixel; grColor pix; extract565( pix16, pix ); compose_pixel( pix, color, val, max ); *pixel = (short)inject565( pix ); } } _write +=2; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } /**************************************************************************/ /* */ /* blit_gray_to_24 */ /* */ /**************************************************************************/ #ifdef GRAY8 static void blit_gray8_to_24( grBlitter* blit, grColor color ) { int y; int sr = color.chroma[0]; int sg = color.chroma[1]; int sb = color.chroma[2]; unsigned char* read; unsigned char* write; read = blit->read + blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { if (val >= 254) { _write[0] = (unsigned char)sr; _write[1] = (unsigned char)sg; _write[2] = (unsigned char)sb; } else if ( val >= 2 ) { int dr = _write[0]; int dg = _write[1]; int db = _write[2]; dr += ((sr-dr)*val) >> 8; dg += ((sg-dg)*val) >> 8; db += ((sb-db)*val) >> 8; _write[0] = (unsigned char)dr; _write[1] = (unsigned char)dg, _write[2] = (unsigned char)db; } } _write += 3; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #endif /* GRAY8 */ static void blit_gray_to_24( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; read = blit->read + blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { if (val == max) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel( pix, color, val, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 3; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } /**************************************************************************/ /* */ /* blit_gray_to_32 */ /* */ /**************************************************************************/ static void blit_gray_to_32( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; read = blit->read + blit->xread; write = blit->write + 4*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val; val = *_read; if (val) { if (val == max) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; _write[3] = color.chroma[3]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel( pix, color, val, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 4; _read ++; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } static void blit_gray8_to_32( grBlitter* blit, grColor color ) { blit_gray_to_32( blit, color, 255 ); } /**************************************************************************/ /* */ /* blit_lcd_to_24 */ /* */ /**************************************************************************/ #ifdef GRAY8 static void blit_lcd8_to_24( grBlitter* blit, grColor color ) { int y; int sr = color.chroma[0]; int sg = color.chroma[1]; int sb = color.chroma[2]; unsigned char* read; unsigned char* write; read = blit->read + 3*blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { int val0, val1, val2; val0 = _read[0]; val1 = _read[1]; val2 = _read[2]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == 255 ) { _write[0] = (unsigned char)sr; _write[1] = (unsigned char)sg; _write[2] = (unsigned char)sb; } else { /* compose gray value */ int dr, dg, db; dr = _write[0]; dr += (sr-dr)*val0 >> 8; dg = _write[1]; dg += (sg-dg)*val1 >> 8; db = _write[1]; db += (sb-db)*val2 >> 8; _write[0] = dr; _write[1] = dg; _write[2] = db; } } _write += 3; _read += 3; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #endif /* GRAY8 */ static void blit_lcd_to_24( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; read = blit->read + 3*blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { int val0, val1, val2; val0 = _read[0]; val1 = _read[1]; val2 = _read[2]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == max ) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel_full( pix, color, val0, val1, val2, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 3; _read += 3; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #ifdef GRAY8 static void blit_lcd28_to_24( grBlitter* blit, grColor color ) { int y; int sr = color.chroma[0]; int sg = color.chroma[1]; int sb = color.chroma[2]; unsigned char* read; unsigned char* write; read = blit->read + 3*blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { int val0, val1, val2; val0 = _read[2]; val1 = _read[1]; val2 = _read[0]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == 255 ) { _write[0] = (unsigned char)sr; _write[1] = (unsigned char)sg; _write[2] = (unsigned char)sb; } else { /* compose gray value */ int dr, dg, db; dr = _write[0]; dr += (sr-dr)*val0 >> 8; dg = _write[1]; dg += (sg-dg)*val1 >> 8; db = _write[1]; db += (sb-db)*val2 >> 8; _write[0] = dr; _write[1] = dg; _write[2] = db; } } _write += 3; _read += 3; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } #endif /* GRAY8 */ static void blit_lcd2_to_24( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; read = blit->read + 3*blit->xread; write = blit->write + 3*blit->xwrite; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { int val0, val1, val2; val0 = _read[2]; val1 = _read[1]; val2 = _read[0]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == max ) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel_full( pix, color, val0, val1, val2, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 3; _read += 3; x--; } read += blit->read_line; write += blit->write_line; y--; } while (y > 0); } /**************************************************************************/ /* */ /* blit_lcdv_to_24 */ /* */ /**************************************************************************/ static void blit_lcdv_to_24( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; long line; read = blit->read + blit->xread; write = blit->write + 3*blit->xwrite; line = blit->read_line; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val0, val1, val2; val0 = _read[0*line]; val1 = _read[1*line]; val2 = _read[2*line]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == max ) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel_full( pix, color, val0, val1, val2, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 3; _read += 1; x--; } read += 3*line; write += blit->write_line; y--; } while (y > 0); } static void blit_lcdv2_to_24( grBlitter* blit, grColor color, int max ) { int y; unsigned char* read; unsigned char* write; long line; read = blit->read + blit->xread; write = blit->write + 3*blit->xwrite; line = blit->read_line; y = blit->height; do { unsigned char* _read = read; unsigned char* _write = write; int x = blit->width; while (x > 0) { unsigned char val0, val1, val2; val0 = _read[2*line]; val1 = _read[1*line]; val2 = _read[0*line]; if ( val0 | val1 | val2 ) { if ( val0 == val1 && val0 == val2 && val0 == max ) { _write[0] = color.chroma[0]; _write[1] = color.chroma[1]; _write[2] = color.chroma[2]; } else { /* compose gray value */ grColor pix; pix.chroma[0] = _write[0]; pix.chroma[1] = _write[1]; pix.chroma[2] = _write[2]; compose_pixel_full( pix, color, val0, val1, val2, max ); _write[0] = pix.chroma[0]; _write[1] = pix.chroma[1]; _write[2] = pix.chroma[2]; } } _write += 3; _read += 1; x--; } read += 3*line; write += blit->write_line; y--; } while (y > 0); } /********************************************************************** * * * grBlitGlyphBitmap * * * writes a given glyph bitmap to a target surface. * * * surface :: handle to target surface * x :: position of left-most pixel of glyph image in surface * y :: position of top-most pixel of glyph image in surface * bitmap :: source glyph image * * * Error code. 0 means success * **********************************************************************/ typedef void (*grColorGlyphBlitter)( grBlitter* blit, grColor color, int max_gray ); static const grColorGlyphBlitter gr_color_blitters[gr_pixel_mode_max] = { 0, 0, 0, 0, 0, blit_gray_to_555, blit_gray_to_565, blit_gray_to_24, blit_gray_to_32 }; #ifdef GRAY8 typedef void (*grGray8GlyphBlitter)( grBlitter* blit, grColor color ); static const grGray8GlyphBlitter gr_gray8_blitters[gr_pixel_mode_max] = { 0, 0, 0, 0, 0, blit_gray8_to_555, blit_gray8_to_565, blit_gray8_to_24, blit_gray8_to_32 }; #endif #include "gblblit.h" static double gr_glyph_gamma = 1.0; void grSetGlyphGamma( double gamma ) { gr_glyph_gamma = gamma; } int grBlitGlyphToBitmap( grBitmap* target, grBitmap* glyph, grPos x, grPos y, grColor color ) { grBlitter blit; grPixelMode mode; /* check arguments */ if ( !target || !glyph ) { grError = gr_err_bad_argument; return -1; } /* short cut to alpha blender for certain glyph types */ { GBlenderSourceFormat src_format; GBlenderTargetFormat dst_format; int width, height; GBlenderBlitRec gblit[1]; GBlenderPixel gcolor; static GBlenderRec gblender[1]; static double gblender_gamma = -100.0; if ( glyph->grays != 256 ) goto DefaultBlit; switch ( glyph->mode ) { case gr_pixel_mode_gray: src_format = GBLENDER_SOURCE_GRAY8; break; case gr_pixel_mode_lcd: src_format = GBLENDER_SOURCE_HRGB; break; case gr_pixel_mode_lcdv: src_format = GBLENDER_SOURCE_VRGB; break; case gr_pixel_mode_lcd2: src_format = GBLENDER_SOURCE_HBGR; break; case gr_pixel_mode_lcdv2: src_format = GBLENDER_SOURCE_VBGR; break; default: goto DefaultBlit; } width = glyph->width; height = glyph->rows; if ( glyph->mode == gr_pixel_mode_lcd || glyph->mode == gr_pixel_mode_lcd2 ) width /= 3; if ( glyph->mode == gr_pixel_mode_lcdv || glyph->mode == gr_pixel_mode_lcdv2 ) height /= 3; switch ( target->mode ) { case gr_pixel_mode_rgb32: dst_format = GBLENDER_TARGET_RGB32; break; case gr_pixel_mode_rgb24: dst_format = GBLENDER_TARGET_RGB24; break; case gr_pixel_mode_rgb565: dst_format = GBLENDER_TARGET_RGB565; break; default: goto DefaultBlit; } /* initialize blender when needed, i.e. when gamma changes */ if ( gblender_gamma != gr_glyph_gamma ) { gblender_gamma = gr_glyph_gamma; gblender_init( gblender, gblender_gamma ); } if ( gblender_blit_init( gblit, gblender, x, y, src_format, glyph->buffer, glyph->pitch, width, height, dst_format, target->buffer, target->pitch, target->width, target->rows ) < 0 ) { /* nothing to do */ return 0; } gcolor = ((GBlenderPixel)color.chroma[0] << 16) | ((GBlenderPixel)color.chroma[1] << 8 ) | ((GBlenderPixel)color.chroma[2] ) ; gblender_blit_run( gblit, gcolor ); return 1; } DefaultBlit: /* set up blitter and compute clipping. Return immediately if needed */ blit.source = *glyph; blit.target = *target; mode = target->mode; if ( compute_clips( &blit, x, y ) ) return 0; switch ( glyph->mode ) { case gr_pixel_mode_mono: /* handle monochrome bitmap blitting */ if ( mode <= gr_pixel_mode_none || mode >= gr_pixel_mode_max ) { grError = gr_err_bad_source_depth; return -1; } gr_mono_blitters[mode]( &blit, color ); break; case gr_pixel_mode_gray: if ( glyph->grays > 1 ) { int target_grays = target->grays; int source_grays = glyph->grays; const byte* saturation; if ( mode == gr_pixel_mode_gray && target_grays > 1 ) { /* rendering into a gray target - use special composition */ /* routines.. */ if ( gr_last_saturation->count == target_grays ) saturation = gr_last_saturation->table; else { saturation = grGetSaturation( target_grays ); if ( !saturation ) return -3; } if ( target_grays == source_grays ) blit_gray_to_gray_simple( &blit, saturation ); else { const byte* conversion; if ( gr_last_conversion->target_grays == target_grays && gr_last_conversion->source_grays == source_grays ) conversion = gr_last_conversion->table; else { conversion = grGetConversion( target_grays, source_grays ); if ( !conversion ) return -3; } blit_gray_to_gray( &blit, saturation, conversion ); } } else { /* rendering into a color target */ if ( mode <= gr_pixel_mode_gray || mode >= gr_pixel_mode_max ) { grError = gr_err_bad_target_depth; return -1; } #ifdef GRAY8 if ( source_grays == 256 ) gr_gray8_blitters[mode]( &blit, color ); else #endif /* GRAY8 */ gr_color_blitters[mode]( &blit, color, source_grays - 1 ); } } break; case gr_pixel_mode_lcd: if ( mode == gr_pixel_mode_rgb24 ) { #ifdef GRAY8 if ( glyph->grays == 256 ) blit_lcd8_to_24( &blit, color ); else #endif if ( glyph->grays > 1 ) blit_lcd_to_24( &blit, color, glyph->grays-1 ); } break; case gr_pixel_mode_lcdv: if ( glyph->grays > 1 && mode == gr_pixel_mode_rgb24 ) { blit_lcdv_to_24( &blit, color, glyph->grays-1 ); break; } case gr_pixel_mode_lcd2: if ( mode == gr_pixel_mode_rgb24 ) { #ifdef GRAY8 if ( glyph->grays == 256 ) blit_lcd28_to_24( &blit, color ); else #endif if ( glyph->grays > 1 ) blit_lcd2_to_24( &blit, color, glyph->grays-1 ); } break; case gr_pixel_mode_lcdv2: if ( mode == gr_pixel_mode_rgb24 ) { if ( glyph->grays > 1 ) blit_lcdv2_to_24( &blit, color, glyph->grays-1 ); } break; default: /* we don't support the blitting of bitmaps of the following */ /* types : pal4, pal8, rgb555, rgb565, rgb24, rgb32 */ /* */ grError = gr_err_bad_source_depth; return -2; } return 0; } /* End */