/** * 将色彩类型为RGBA的前景图像,合成至目标背景图像中 * param back * 背景图像 * param des_rect * 背景图像中的写入区域 * param fore * 前景图像 * param src_pos * 前景图像中的读取区域的坐标 * warning * 此函数不会对传入的参数进行有效性判断,因为此函数主要被Graph_Mix函 * 数调用,Graph_Mix函数会预先进行参数有效性判断 */ static void Graph_RGBAMix( LCUI_Graph *des, LCUI_Rect des_rect, LCUI_Graph *src, LCUI_Pos src_pos ) { int x, y; int src_n, des_n; int des_row_start, src_row_start; /* 计算并保存第一行的首个像素的位置 */ src_row_start = src_pos.y * src->w + src_pos.x; des_row_start = des_rect.y * des->w + des_rect.x; for(y=0; y<des_rect.height; ++y) { des_n = des_row_start; src_n = src_row_start; for(x=0; x<des_rect.width; ++x) { /* 将R、G、B三个色彩值进行alpha混合 */ ALPHA_BLEND( src->rgba[0][src_n], des->rgba[0][des_n], src->rgba[3][src_n] ); ALPHA_BLEND( src->rgba[1][src_n], des->rgba[1][des_n], src->rgba[3][src_n] ); ALPHA_BLEND( src->rgba[2][src_n], des->rgba[2][des_n], src->rgba[3][src_n] ); /* 切换到下个像素的数据 */ ++src_n; ++des_n; } /* 切换到下一行像素 */ des_row_start += des->w; src_row_start += src->w; } }
/** * 将色彩类型为RGB的前景图像,合成至目标背景图像中 * 在进行alpha混合时,会将源图像的全局透明度计算在内进行混合 * param back * 背景图像 * param des_rect * 背景图像中的写入区域 * param fore * 前景图像 * param src_pos * 前景图像中的读取区域的坐标 * warning * 此函数不会对传入的参数进行有效性判断,因为此函数主要被Graph_Mix函 * 数调用,Graph_Mix函数会预先进行参数有效性判断 */ static void Graph_RGBMixWithGlobalAlpha( LCUI_Graph *des, LCUI_Rect des_rect, LCUI_Graph *src, LCUI_Pos src_pos ) { int x, y; int src_n, des_n; int des_row_start, src_row_start; src_row_start = src_pos.y * src->w + src_pos.x; des_row_start = des_rect.y * src->w + des_rect.x; for(y=0; y<des_rect.height; ++y) { des_n = des_row_start; src_n = src_row_start; for(x=0; x<des_rect.width; ++x) { ALPHA_BLEND( src->rgba[0][src_n], des->rgba[0][des_n], src->alpha ); ALPHA_BLEND( src->rgba[1][src_n], des->rgba[1][des_n], src->alpha ); ALPHA_BLEND( src->rgba[2][src_n], des->rgba[2][des_n], src->alpha ); ++des_n; ++src_n; } } }
extern inline void mix_pixel( uchar_t **buff, int pos, LCUI_RGB color, uchar_t alpha ) { ALPHA_BLEND( color.red, buff[0][pos], alpha ); ALPHA_BLEND( color.blue, buff[1][pos], alpha ); ALPHA_BLEND( color.green, buff[2][pos], alpha ); }
static void Graph_ARGBMixARGB( LCUI_Graph *des, LCUI_Rect des_rect, const LCUI_Graph *src, LCUI_Pos src_pos ) { int x, y, val; uchar_t alpha; LCUI_ARGB *px_src, *px_des; LCUI_ARGB *px_row_src, *px_row_des; /* 计算并保存第一行的首个像素的位置 */ px_row_src = src->argb + src_pos.y*src->w + src_pos.x; px_row_des = des->argb + des_rect.y*des->w + des_rect.x; if( src->opacity < 1.0 ) { for( y=0; y<des_rect.h; ++y ) { px_src = px_row_src; px_des = px_row_des; for( x=0; x<des_rect.w; ++x ) { alpha = px_src->a * src->opacity; /* 将R、G、B三个色彩值进行alpha混合 */ ALPHA_BLEND( px_des->r, px_src->r, alpha ); ALPHA_BLEND( px_des->g, px_src->g, alpha ); ALPHA_BLEND( px_des->b, px_src->b, alpha ); if( px_des->alpha == 255 || px_src->alpha == 255 ) { px_des->alpha = 255; } else { /* alpha = 1.0 - (1.0 - a1)*(1.0 - a2) */ val = (255 - px_src->alpha)*(255 - px_des->alpha); px_des->alpha = (uchar_t)(255 - val / 65025); } /* 切换到下个像素的数据 */ ++px_src; ++px_des; } /* 切换到下一行像素 */ px_row_des += des->w; px_row_src += src->w; } return; } for( y=0; y<des_rect.h; ++y ) { px_src = px_row_src; px_des = px_row_des; for( x=0; x<des_rect.w; ++x ) { ALPHA_BLEND( px_des->r, px_src->r, px_src->a ); ALPHA_BLEND( px_des->g, px_src->g, px_src->a ); ALPHA_BLEND( px_des->b, px_src->b, px_src->a ); if( px_des->alpha == 255 || px_src->alpha == 255 ) { px_des->alpha = 255; } else { val = (255 - px_src->alpha)*(255 - px_des->alpha); px_des->alpha = (uchar_t)(255 - val / 65025); } ++px_src; ++px_des; } px_row_des += des->w; px_row_src += src->w; } }
/** * 将色彩类型为RGBA的前景图像,合成至目标背景图像中 * 在进行alpha混合时,会将源图像的全局透明度计算在内进行混合 * param back * 背景图像 * param des_rect * 背景图像中的写入区域 * param fore * 前景图像 * param src_pos * 前景图像中的读取区域的坐标 * warning * 此函数不会对传入的参数进行有效性判断,因为此函数主要被Graph_Mix函 * 数调用,Graph_Mix函数会预先进行参数有效性判断 */ static void Graph_RGBAMixWithGlobalAlpha( LCUI_Graph *des, LCUI_Rect des_rect, LCUI_Graph *src, LCUI_Pos src_pos ) { double k; int x, y; uchar_t alpha; int src_n, des_n; int des_row_start, src_row_start; src_row_start = src_pos.y * src->w + src_pos.x; des_row_start = des_rect.y * des->w + des_rect.x; /* 先得出透明度比例,避免在循环中进行除法运算 */ k = src->alpha / 255.0; for (y=0; y < des_rect.height; ++y) { des_n = des_row_start; src_n = src_row_start; for(x=0; x<des_rect.width; ++x) { alpha = src->rgba[3][src_n] * k; ALPHA_BLEND( src->rgba[0][src_n], des->rgba[0][des_n], alpha ); ALPHA_BLEND( src->rgba[1][src_n], des->rgba[1][des_n], alpha ); ALPHA_BLEND( src->rgba[2][src_n], des->rgba[2][des_n], alpha ); ++des_n; ++src_n; } src_row_start += src->w; des_row_start += des->w; } }
static void Blit1toNAlphaKey(SDL_BlitInfo *info) { int width = info->d_width; int height = info->d_height; int srcskip = info->s_skip; int dstskip = info->d_skip; SDL_PixelFormat *srcfmt = info->src; SDL_PixelFormat *dstfmt = info->dst; const SDL_Color *srcpal = info->src->palette->colors; uint32_t ckey = srcfmt->colorkey; const int A = srcfmt->alpha; int dstbpp = dstfmt->BytesPerPixel; uint8_t *src = info->s_pixels; uint8_t *dst = info->d_pixels; while ( height-- ) { int dR, dG, dB; int n; for (n = width; n > 0; --n) { if ( *src != ckey ) { uint32_t pixel; int sR = srcpal[*src].r; int sG = srcpal[*src].g; int sB = srcpal[*src].b; DISEMBLE_RGB(dst, dstbpp, dstfmt, &pixel, &dR, &dG, &dB); ALPHA_BLEND(sR, sG, sB, A, &dR, &dG, &dB); ASSEMBLE_RGB(dst, dstbpp, dstfmt, dR, dG, dB); } src++; dst += dstbpp; } src += srcskip; dst += dstskip; } }
/** 将字体位图绘制到目标图像上 */ int FontBMP_Mix( LCUI_Graph *graph, LCUI_Pos pos, LCUI_FontBMP *bmp, LCUI_Color color ) { int val, x, y; LCUI_Graph *des; LCUI_Rect des_rect, cut; LCUI_ARGB *px_des, *px_row_des; uchar_t *bmp_src, *bmp_row_src, *byte_row_des, *byte_des; /* 数据有效性检测 */ if( !FontBMP_IsValid( bmp ) || !Graph_IsValid( graph ) ) { return -1; } /* 获取背景图形的有效区域 */ Graph_GetValidRect( graph, &des_rect ); /* 获取背景图引用的源图形 */ des = Graph_GetQuote( graph ); /* 起点位置的有效性检测 */ if(pos.x > des->w || pos.y > des->h) { return -2; } /* 获取需要裁剪的区域 */ LCUIRect_GetCutArea( Size( des_rect.width, des_rect.height ), Rect( pos.x, pos.y, bmp->width, bmp->rows ), &cut ); pos.x += cut.x; pos.y += cut.y; if( graph->color_type == COLOR_TYPE_ARGB ) { bmp_row_src = bmp->buffer + cut.y*bmp->width + cut.x; px_row_des = des->argb + (pos.y + des_rect.y) * des->w; px_row_des += pos.x + des_rect.x; for( y=0; y<cut.h; ++y ) { bmp_src = bmp_row_src; px_des = px_row_des; for( x=0; x<cut.w; ++x ) { ALPHA_BLEND( px_des->r, color.r, *bmp_src ); ALPHA_BLEND( px_des->g, color.g, *bmp_src ); ALPHA_BLEND( px_des->b, color.b, *bmp_src ); if( px_des->alpha == 255 || *bmp_src == 255 ) { px_des->alpha = 255; } else { val = (255 - *bmp_src)*(255 - px_des->alpha); px_des->alpha = (uchar_t)(255 - val / 65025); } ++bmp_src; ++px_des; } px_row_des += des->w; bmp_row_src += bmp->width; } return 0; } bmp_row_src = bmp->buffer + cut.y*bmp->width + cut.x; byte_row_des = des->bytes + (pos.y + des_rect.y) * des->bytes_per_row; byte_row_des += (pos.x + des_rect.x)*des->bytes_per_pixel; for( y=0; y<cut.h; ++y ) { bmp_src = bmp_row_src; byte_des = byte_row_des; for( x=0; x<cut.w; ++x ) { ALPHA_BLEND( *byte_des, color.b, *bmp_src ); byte_des++; ALPHA_BLEND( *byte_des, color.g, *bmp_src ); byte_des++; ALPHA_BLEND( *byte_des, color.r, *bmp_src ); byte_des++; ++bmp_src; } byte_row_des += des->w*3; bmp_row_src += bmp->width; } return 0; }