diff options
Diffstat (limited to 'common/lcd.c')
| -rw-r--r-- | common/lcd.c | 178 | 
1 files changed, 174 insertions, 4 deletions
| diff --git a/common/lcd.c b/common/lcd.c index 301760473..4778655a2 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -696,6 +696,138 @@ static void splash_align_axis(int *axis, unsigned long panel_size,  }  #endif + +#ifdef CONFIG_LCD_BMP_RLE8 + +#define BMP_RLE8_ESCAPE		0 +#define BMP_RLE8_EOL		0 +#define BMP_RLE8_EOBMP		1 +#define BMP_RLE8_DELTA		2 + +static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap, +				  int cnt) +{ +	while (cnt > 0) { +		*(*fbp)++ = cmap[*bmap++]; +		cnt--; +	} +} + +static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) +{ +	ushort *fb = *fbp; +	int cnt_8copy = cnt >> 3; + +	cnt -= cnt_8copy << 3; +	while (cnt_8copy > 0) { +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		cnt_8copy--; +	} +	while (cnt > 0) { +		*fb++ = c; +		cnt--; +	} +	(*fbp) = fb; +} + +/* + * Do not call this function directly, must be called from + * lcd_display_bitmap. + */ +static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb, +				    int x_off, int y_off) +{ +	uchar *bmap; +	ulong width, height; +	ulong cnt, runlen; +	int x, y; +	int decode = 1; + +	width = le32_to_cpu(bmp->header.width); +	height = le32_to_cpu(bmp->header.height); +	bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset); + +	x = 0; +	y = height - 1; + +	while (decode) { +		if (bmap[0] == BMP_RLE8_ESCAPE) { +			switch (bmap[1]) { +			case BMP_RLE8_EOL: +				/* end of line */ +				bmap += 2; +				x = 0; +				y--; +				/* 16bpix, 2-byte per pixel, width should *2 */ +				fb -= (width * 2 + lcd_line_length); +				break; +			case BMP_RLE8_EOBMP: +				/* end of bitmap */ +				decode = 0; +				break; +			case BMP_RLE8_DELTA: +				/* delta run */ +				x += bmap[2]; +				y -= bmap[3]; +				/* 16bpix, 2-byte per pixel, x should *2 */ +				fb = (uchar *) (lcd_base + (y + y_off - 1) +					* lcd_line_length + (x + x_off) * 2); +				bmap += 4; +				break; +			default: +				/* unencoded run */ +				runlen = bmap[1]; +				bmap += 2; +				if (y < height) { +					if (x < width) { +						if (x + runlen > width) +							cnt = width - x; +						else +							cnt = runlen; +						draw_unencoded_bitmap( +							(ushort **)&fb, +							bmap, cmap, cnt); +					} +					x += runlen; +				} +				bmap += runlen; +				if (runlen & 1) +					bmap++; +			} +		} else { +			/* encoded run */ +			if (y < height) { +				runlen = bmap[0]; +				if (x < width) { +					/* aggregate the same code */ +					while (bmap[0] == 0xff && +					       bmap[2] != BMP_RLE8_ESCAPE && +					       bmap[1] == bmap[3]) { +						runlen += bmap[2]; +						bmap += 2; +					} +					if (x + runlen > width) +						cnt = width - x; +					else +						cnt = runlen; +					draw_encoded_bitmap((ushort **)&fb, +						cmap[bmap[1]], cnt); +				} +				x += runlen; +			} +			bmap += 2; +		} +	} +} +#endif +  #if defined(CONFIG_MPC823) || defined(CONFIG_MCC200)  #define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++)  #else @@ -729,7 +861,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	uchar *fb;  	bmp_image_t *bmp=(bmp_image_t *)bmp_image;  	uchar *bmap; -	ushort padded_line; +	ushort padded_width;  	unsigned long width, height, byte_width;  	unsigned long pwidth = panel_info.vl_col;  	unsigned colors, bpix, bmp_bpix; @@ -816,7 +948,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	}  #endif -	padded_line = (width&0x3) ? ((width&~0x3)+4) : (width); +	padded_width = (width&0x3) ? ((width&~0x3)+4) : (width);  #ifdef CONFIG_SPLASH_SCREEN_ALIGN  	splash_align_axis(&x, pwidth, width); @@ -835,6 +967,18 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	switch (bmp_bpix) {  	case 1: /* pass through */  	case 8: +#ifdef CONFIG_LCD_BMP_RLE8 +		if (le32_to_cpu(bmp->header.compression) == BMP_BI_RLE8) { +			if (bpix != 16) { +				/* TODO implement render code for bpix != 16 */ +				printf("Error: only support 16 bpix"); +				return 1; +			} +			lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y); +			break; +		} +#endif +  		if (bpix != 16)  			byte_width = width;  		else @@ -850,7 +994,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  					fb += sizeof(uint16_t) / sizeof(*fb);  				}  			} -			bmap += (width - padded_line); +			bmap += (padded_width - width);  			fb   -= (byte_width + lcd_line_length);  		}  		break; @@ -862,7 +1006,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  			for (j = 0; j < width; j++)  				fb_put_word(&fb, &bmap); -			bmap += (padded_line - width) * 2; +			bmap += (padded_width - width) * 2;  			fb   -= (width * 2 + lcd_line_length);  		}  		break; @@ -940,5 +1084,31 @@ static void *lcd_logo(void)  #endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */  } +void lcd_position_cursor(unsigned col, unsigned row) +{ +	console_col = min(col, CONSOLE_COLS - 1); +	console_row = min(row, CONSOLE_ROWS - 1); +} + +int lcd_get_pixel_width(void) +{ +	return panel_info.vl_col; +} + +int lcd_get_pixel_height(void) +{ +	return panel_info.vl_row; +} + +int lcd_get_screen_rows(void) +{ +	return CONSOLE_ROWS; +} + +int lcd_get_screen_columns(void) +{ +	return CONSOLE_COLS; +} +  /************************************************************************/  /************************************************************************/ |