From 0250be1d6799db7b5ddc99cb33f31bf9cff01ed2 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sun, 15 Jun 2014 18:26:44 +0200 Subject: lcd-16bit: Split out some functions to lcd-color-common.c An upcoming lcd-24bit.c driver will re-use a lot of code from the 16bit drivers, so prepare for that. Change-Id: I7bc7f6b992e5e3f4e0a0aa54dc08103ebb05315f --- firmware/drivers/lcd-16bit-common.c | 574 ---------------------------------- firmware/drivers/lcd-16bit.c | 12 +- firmware/drivers/lcd-color-common.c | 605 ++++++++++++++++++++++++++++++++++++ 3 files changed, 616 insertions(+), 575 deletions(-) create mode 100644 firmware/drivers/lcd-color-common.c (limited to 'firmware') diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c index 93e7c2e012..d006b3900a 100644 --- a/firmware/drivers/lcd-16bit-common.c +++ b/firmware/drivers/lcd-16bit-common.c @@ -28,44 +28,6 @@ #error ROW_INC or COL_INC not defined #endif -enum fill_opt { - OPT_NONE = 0, - OPT_SET, - OPT_COPY -}; - -/*** globals ***/ -fb_data lcd_static_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH] - IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16); -fb_data *lcd_framebuffer = &lcd_static_framebuffer[0][0]; - -static fb_data* lcd_backdrop = NULL; -static long lcd_backdrop_offset IDATA_ATTR = 0; - -static struct viewport default_vp = -{ - .x = 0, - .y = 0, - .width = LCD_WIDTH, - .height = LCD_HEIGHT, - .font = FONT_SYSFIXED, - .drawmode = DRMODE_SOLID, - .fg_pattern = LCD_DEFAULT_FG, - .bg_pattern = LCD_DEFAULT_BG, -}; - -static struct viewport* current_vp IDATA_ATTR = &default_vp; - -/* LCD init */ -void lcd_init(void) -{ - lcd_clear_display(); - - /* Call device specific init */ - lcd_init_device(); - scroll_init(); -} - /* Clear the current viewport */ void lcd_clear_viewport(void) { @@ -146,70 +108,6 @@ void lcd_clear_viewport(void) lcd_scroll_stop_viewport(current_vp); } -/*** parameter handling ***/ - -void lcd_set_drawmode(int mode) -{ - current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); -} - -int lcd_get_drawmode(void) -{ - return current_vp->drawmode; -} - -void lcd_set_foreground(unsigned color) -{ - current_vp->fg_pattern = color; -} - -unsigned lcd_get_foreground(void) -{ - return current_vp->fg_pattern; -} - -void lcd_set_background(unsigned color) -{ - current_vp->bg_pattern = color; -} - -unsigned lcd_get_background(void) -{ - return current_vp->bg_pattern; -} - -void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color) -{ - lcd_set_drawmode(mode); - current_vp->fg_pattern = fg_color; - current_vp->bg_pattern = bg_color; -} - -int lcd_getwidth(void) -{ - return current_vp->width; -} - -int lcd_getheight(void) -{ - return current_vp->height; -} - -void lcd_setfont(int newfont) -{ - current_vp->font = newfont; -} - -int lcd_getfont(void) -{ - return current_vp->font; -} - -int lcd_getstringsize(const unsigned char *str, int *w, int *h) -{ - return font_getstringsize(str, w, h, current_vp->font); -} - /*** low-level drawing functions ***/ static void ICODE_ATTR setpixel(fb_data *address) @@ -249,155 +147,6 @@ lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = { lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; -void lcd_set_backdrop(fb_data* backdrop) -{ - lcd_backdrop = backdrop; - if (backdrop) - { - lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer; - lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop; - } - else - { - lcd_backdrop_offset = 0; - lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; - } -} - -fb_data* lcd_get_backdrop(void) -{ - return lcd_backdrop; -} - -/* Clear the whole display */ -void lcd_clear_display(void) -{ - struct viewport* old_vp = current_vp; - - current_vp = &default_vp; - - lcd_clear_viewport(); - - current_vp = old_vp; -} - -/* Set a single pixel */ -void lcd_drawpixel(int x, int y) -{ - if ( ((unsigned)x < (unsigned)current_vp->width) - && ((unsigned)y < (unsigned)current_vp->height) -#if defined(HAVE_VIEWPORT_CLIP) - && ((unsigned)x < (unsigned)LCD_WIDTH) - && ((unsigned)y < (unsigned)LCD_HEIGHT) -#endif - ) - lcd_fastpixelfuncs[current_vp->drawmode](FBADDR(current_vp->x+x, current_vp->y+y)); -} - -/* Draw a line */ -void lcd_drawline(int x1, int y1, int x2, int y2) -{ - int numpixels; - int i; - int deltax, deltay; - int d, dinc1, dinc2; - int x, xinc1, xinc2; - int y, yinc1, yinc2; - lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; - - deltay = abs(y2 - y1); - if (deltay == 0) - { - /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */ - lcd_hline(x1, x2, y1); - return; - } - deltax = abs(x2 - x1); - if (deltax == 0) - { - /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */ - lcd_vline(x1, y1, y2); - return; - } - xinc2 = 1; - yinc2 = 1; - - if (deltax >= deltay) - { - numpixels = deltax; - d = 2 * deltay - deltax; - dinc1 = deltay * 2; - dinc2 = (deltay - deltax) * 2; - xinc1 = 1; - yinc1 = 0; - } - else - { - numpixels = deltay; - d = 2 * deltax - deltay; - dinc1 = deltax * 2; - dinc2 = (deltax - deltay) * 2; - xinc1 = 0; - yinc1 = 1; - } - numpixels++; /* include endpoints */ - - if (x1 > x2) - { - xinc1 = -xinc1; - xinc2 = -xinc2; - } - - if (y1 > y2) - { - yinc1 = -yinc1; - yinc2 = -yinc2; - } - - x = x1; - y = y1; - - for (i = 0; i < numpixels; i++) - { - if ( ((unsigned)x < (unsigned)current_vp->width) - && ((unsigned)y < (unsigned)current_vp->height) -#if defined(HAVE_VIEWPORT_CLIP) - && ((unsigned)x < (unsigned)LCD_WIDTH) - && ((unsigned)y < (unsigned)LCD_HEIGHT) -#endif - ) - pfunc(FBADDR(x + current_vp->x, y + current_vp->y)); - - if (d < 0) - { - d += dinc1; - x += xinc1; - y += yinc1; - } - else - { - d += dinc2; - x += xinc2; - y += yinc2; - } - } -} - -/* Draw a rectangular box */ -void lcd_drawrect(int x, int y, int width, int height) -{ - if ((width <= 0) || (height <= 0)) - return; - - int x2 = x + width - 1; - int y2 = y + height - 1; - - lcd_vline(x, y, y2); - lcd_vline(x2, y, y2); - lcd_hline(x, x2, y); - lcd_hline(x, x2, y2); -} - /* Fill a rectangular area */ void lcd_fillrect(int x, int y, int width, int height) { @@ -1087,326 +836,3 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, BLEND_FINISH; } - -/* Draw a full native bitmap */ -void lcd_bitmap(const fb_data *src, int x, int y, int width, int height) -{ - lcd_bitmap_part(src, 0, 0, STRIDE(SCREEN_MAIN, width, height), x, y, width, height); -} - -/* Draw a full native bitmap with a transparent color */ -void lcd_bitmap_transparent(const fb_data *src, int x, int y, - int width, int height) -{ - lcd_bitmap_transparent_part(src, 0, 0, - STRIDE(SCREEN_MAIN, width, height), x, y, width, height); -} - -/* draw alpha bitmap for anti-alias font */ -void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, - int src_y, int stride, int x, int y, - int width, int height) -{ - lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride); -} - -/* Draw a partial bitmap (mono or native) including alpha channel */ -void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, - int x, int y, int width, int height) -{ - int bitmap_stride = STRIDE_MAIN(bm->width, bm->height); - if (bm->format == FORMAT_MONO) - lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height); - else if (bm->alpha_offset > 0) - lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset, - src_x, src_y, x, y, width, height, - bitmap_stride, ALIGN_UP(bm->width, 2)); - else - lcd_bitmap_transparent_part((fb_data*)bm->data, - src_x, src_y, bitmap_stride, x, y, width, height); -} - -/* Draw a native bitmap with alpha channel */ -void ICODE_ATTR lcd_bmp(const struct bitmap *bmp, int x, int y) -{ - lcd_bmp_part(bmp, 0, 0, x, y, bmp->width, bmp->height); -} - -/** - * |R| |1.000000 -0.000001 1.402000| |Y'| - * |G| = |1.000000 -0.334136 -0.714136| |Pb| - * |B| |1.000000 1.772000 0.000000| |Pr| - * Scaled, normalized, rounded and tweaked to yield RGB 565: - * |R| |74 0 101| |Y' - 16| >> 9 - * |G| = |74 -24 -51| |Cb - 128| >> 8 - * |B| |74 128 0| |Cr - 128| >> 9 - */ -#define YFAC (74) -#define RVFAC (101) -#define GUFAC (-24) -#define GVFAC (-51) -#define BUFAC (128) - -static inline int clamp(int val, int min, int max) -{ - if (val < min) - val = min; - else if (val > max) - val = max; - return val; -} - -#ifndef _WIN32 -/* - * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52 - * When building win32 simulators, we won't be using an optimized version of - * lcd_blit_yuv(), so just don't use the weak attribute. - */ -__attribute__((weak)) -#endif -void lcd_yuv_set_options(unsigned options) -{ - (void)options; -} - -/* Draw a partial YUV colour bitmap */ -#ifndef _WIN32 -__attribute__((weak)) -#endif -void lcd_blit_yuv(unsigned char * const src[3], - int src_x, int src_y, int stride, - int x, int y, int width, int height) -{ - const unsigned char *ysrc, *usrc, *vsrc; - int linecounter; - fb_data *dst, *row_end; - long z; - - /* width and height must be >= 2 and an even number */ - width &= ~1; - linecounter = height >> 1; - -#if LCD_WIDTH >= LCD_HEIGHT - dst = FBADDR(x, y); - row_end = dst + width; -#else - dst = FBADDR(LCD_WIDTH - y - 1, x); - row_end = dst + LCD_WIDTH * width; -#endif - - z = stride * src_y; - ysrc = src[0] + z + src_x; - usrc = src[1] + (z >> 2) + (src_x >> 1); - vsrc = src[2] + (usrc - src[1]); - - /* stride => amount to jump from end of last row to start of next */ - stride -= width; - - /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ - - do - { - do - { - int y, cb, cr, rv, guv, bu, r, g, b; - - y = YFAC*(*ysrc++ - 16); - cb = *usrc++ - 128; - cr = *vsrc++ - 128; - - rv = RVFAC*cr; - guv = GUFAC*cb + GVFAC*cr; - bu = BUFAC*cb; - - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - - y = YFAC*(*ysrc++ - 16); - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - } - while (dst < row_end); - - ysrc += stride; - usrc -= width >> 1; - vsrc -= width >> 1; - -#if LCD_WIDTH >= LCD_HEIGHT - row_end += LCD_WIDTH; - dst += LCD_WIDTH - width; -#else - row_end -= 1; - dst -= LCD_WIDTH*width + 1; -#endif - - do - { - int y, cb, cr, rv, guv, bu, r, g, b; - - y = YFAC*(*ysrc++ - 16); - cb = *usrc++ - 128; - cr = *vsrc++ - 128; - - rv = RVFAC*cr; - guv = GUFAC*cb + GVFAC*cr; - bu = BUFAC*cb; - - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - - y = YFAC*(*ysrc++ - 16); - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - } - while (dst < row_end); - - ysrc += stride; - usrc += stride >> 1; - vsrc += stride >> 1; - -#if LCD_WIDTH >= LCD_HEIGHT - row_end += LCD_WIDTH; - dst += LCD_WIDTH - width; -#else - row_end -= 1; - dst -= LCD_WIDTH*width + 1; -#endif - } - while (--linecounter > 0); - -#if LCD_WIDTH >= LCD_HEIGHT - lcd_update_rect(x, y, width, height); -#else - lcd_update_rect(LCD_WIDTH - y - height, x, height, width); -#endif -} - -/* Fill a rectangle with a gradient. This function draws only the partial - * gradient. It assumes the original gradient is src_height high and skips - * the first few rows. This is useful for drawing only the bottom half of - * a full gradient. - * - * height == src_height and row_skip == 0 will draw the full gradient - * - * x, y, width, height - dimensions describing the rectangle - * start_rgb - beginning color of the gradient - * end_rgb - end color of the gradient - * src_height - assumed original height (only height rows will be drawn) - * row_skip - how many rows of the original gradient to skip - */ -void lcd_gradient_fillrect_part(int x, int y, int width, int height, - unsigned start_rgb, unsigned end_rgb, int src_height, int row_skip) -{ - int old_pattern = current_vp->fg_pattern; - int step_mul, i; - int x1, x2; - x1 = x; - x2 = x + width; - - if (height == 0) return; - - step_mul = (1 << 16) / src_height; - int h_r = RGB_UNPACK_RED(start_rgb); - int h_g = RGB_UNPACK_GREEN(start_rgb); - int h_b = RGB_UNPACK_BLUE(start_rgb); - int rstep = (h_r - RGB_UNPACK_RED(end_rgb)) * step_mul; - int gstep = (h_g - RGB_UNPACK_GREEN(end_rgb)) * step_mul; - int bstep = (h_b - RGB_UNPACK_BLUE(end_rgb)) * step_mul; - h_r = (h_r << 16) + (1 << 15); - h_g = (h_g << 16) + (1 << 15); - h_b = (h_b << 16) + (1 << 15); - - if (row_skip > 0) - { - h_r -= rstep * row_skip; - h_g -= gstep * row_skip; - h_b -= bstep * row_skip; - } - - for(i = y; i < y + height; i++) { - current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); - lcd_hline(x1, x2, i); - h_r -= rstep; - h_g -= gstep; - h_b -= bstep; - } - - current_vp->fg_pattern = old_pattern; -} - -/* Fill a rectangle with a gradient. The gradient's color will fade from - * start_rgb to end_rgb over the height of the rectangle - * - * x, y, width, height - dimensions describing the rectangle - * start_rgb - beginning color of the gradient - * end_rgb - end color of the gradient - */ -void lcd_gradient_fillrect(int x, int y, int width, int height, - unsigned start_rgb, unsigned end_rgb) -{ - lcd_gradient_fillrect_part(x, y, width, height, start_rgb, end_rgb, height, 0); -} diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index 4d4166a384..3c99560b6d 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -41,8 +41,18 @@ #define ROW_INC LCD_WIDTH #define COL_INC 1 -#include "lcd-16bit-common.c" +extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[]; +extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[]; + +static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, + const unsigned char *src, int src_x, + int src_y, int x, int y, + int width, int height, + int stride_image, int stride_src); + +#include "lcd-color-common.c" #include "lcd-bitmap-common.c" +#include "lcd-16bit-common.c" /*** drawing functions ***/ diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c new file mode 100644 index 0000000000..e171f08465 --- /dev/null +++ b/firmware/drivers/lcd-color-common.c @@ -0,0 +1,605 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * Copyright (C) 2009 by Karl Kurbjun + * + * Rockbox driver for 16-bit colour LCDs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +/* to be #included by lcd-16bit*.c */ + +#if !defined(ROW_INC) || !defined(COL_INC) +#error ROW_INC or COL_INC not defined +#endif + +enum fill_opt { + OPT_NONE = 0, + OPT_SET, + OPT_COPY +}; + +/*** globals ***/ +fb_data lcd_static_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH] + IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16); +fb_data *lcd_framebuffer = &lcd_static_framebuffer[0][0]; + +static fb_data* lcd_backdrop = NULL; +static long lcd_backdrop_offset IDATA_ATTR = 0; + +static struct viewport default_vp = +{ + .x = 0, + .y = 0, + .width = LCD_WIDTH, + .height = LCD_HEIGHT, + .font = FONT_SYSFIXED, + .drawmode = DRMODE_SOLID, + .fg_pattern = LCD_DEFAULT_FG, + .bg_pattern = LCD_DEFAULT_BG, +}; + +static struct viewport* current_vp IDATA_ATTR = &default_vp; + +/* LCD init */ +void lcd_init(void) +{ + lcd_clear_display(); + + /* Call device specific init */ + lcd_init_device(); + scroll_init(); +} + +/* Clear the whole display */ +void lcd_clear_display(void) +{ + struct viewport* old_vp = current_vp; + + current_vp = &default_vp; + + lcd_clear_viewport(); + + current_vp = old_vp; +} + +/*** parameter handling ***/ + +void lcd_set_drawmode(int mode) +{ + current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); +} + +int lcd_get_drawmode(void) +{ + return current_vp->drawmode; +} + +void lcd_set_foreground(unsigned color) +{ + current_vp->fg_pattern = color; +} + +unsigned lcd_get_foreground(void) +{ + return current_vp->fg_pattern; +} + +void lcd_set_background(unsigned color) +{ + current_vp->bg_pattern = color; +} + +unsigned lcd_get_background(void) +{ + return current_vp->bg_pattern; +} + +void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color) +{ + lcd_set_drawmode(mode); + current_vp->fg_pattern = fg_color; + current_vp->bg_pattern = bg_color; +} + +int lcd_getwidth(void) +{ + return current_vp->width; +} + +int lcd_getheight(void) +{ + return current_vp->height; +} + +void lcd_setfont(int newfont) +{ + current_vp->font = newfont; +} + +int lcd_getfont(void) +{ + return current_vp->font; +} + +int lcd_getstringsize(const unsigned char *str, int *w, int *h) +{ + return font_getstringsize(str, w, h, current_vp->font); +} + +void lcd_set_backdrop(fb_data* backdrop) +{ + lcd_backdrop = backdrop; + if (backdrop) + { + lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer; + lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop; + } + else + { + lcd_backdrop_offset = 0; + lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; + } +} + +fb_data* lcd_get_backdrop(void) +{ + return lcd_backdrop; +} + +/* Set a single pixel */ +void lcd_drawpixel(int x, int y) +{ + if ( ((unsigned)x < (unsigned)current_vp->width) + && ((unsigned)y < (unsigned)current_vp->height) +#if defined(HAVE_VIEWPORT_CLIP) + && ((unsigned)x < (unsigned)LCD_WIDTH) + && ((unsigned)y < (unsigned)LCD_HEIGHT) +#endif + ) + lcd_fastpixelfuncs[current_vp->drawmode](FBADDR(current_vp->x+x, current_vp->y+y)); +} + +/* Draw a line */ +void lcd_drawline(int x1, int y1, int x2, int y2) +{ + int numpixels; + int i; + int deltax, deltay; + int d, dinc1, dinc2; + int x, xinc1, xinc2; + int y, yinc1, yinc2; + lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode]; + + deltay = abs(y2 - y1); + if (deltay == 0) + { + /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */ + lcd_hline(x1, x2, y1); + return; + } + deltax = abs(x2 - x1); + if (deltax == 0) + { + /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */ + lcd_vline(x1, y1, y2); + return; + } + xinc2 = 1; + yinc2 = 1; + + if (deltax >= deltay) + { + numpixels = deltax; + d = 2 * deltay - deltax; + dinc1 = deltay * 2; + dinc2 = (deltay - deltax) * 2; + xinc1 = 1; + yinc1 = 0; + } + else + { + numpixels = deltay; + d = 2 * deltax - deltay; + dinc1 = deltax * 2; + dinc2 = (deltax - deltay) * 2; + xinc1 = 0; + yinc1 = 1; + } + numpixels++; /* include endpoints */ + + if (x1 > x2) + { + xinc1 = -xinc1; + xinc2 = -xinc2; + } + + if (y1 > y2) + { + yinc1 = -yinc1; + yinc2 = -yinc2; + } + + x = x1; + y = y1; + + for (i = 0; i < numpixels; i++) + { + if ( ((unsigned)x < (unsigned)current_vp->width) + && ((unsigned)y < (unsigned)current_vp->height) +#if defined(HAVE_VIEWPORT_CLIP) + && ((unsigned)x < (unsigned)LCD_WIDTH) + && ((unsigned)y < (unsigned)LCD_HEIGHT) +#endif + ) + pfunc(FBADDR(x + current_vp->x, y + current_vp->y)); + + if (d < 0) + { + d += dinc1; + x += xinc1; + y += yinc1; + } + else + { + d += dinc2; + x += xinc2; + y += yinc2; + } + } +} + +/* Draw a rectangular box */ +void lcd_drawrect(int x, int y, int width, int height) +{ + if ((width <= 0) || (height <= 0)) + return; + + int x2 = x + width - 1; + int y2 = y + height - 1; + + lcd_vline(x, y, y2); + lcd_vline(x2, y, y2); + lcd_hline(x, x2, y); + lcd_hline(x, x2, y2); +} + + +/* Draw a full native bitmap */ +void lcd_bitmap(const fb_data *src, int x, int y, int width, int height) +{ + lcd_bitmap_part(src, 0, 0, STRIDE(SCREEN_MAIN, width, height), x, y, width, height); +} + +/* Draw a full native bitmap with a transparent color */ +void lcd_bitmap_transparent(const fb_data *src, int x, int y, + int width, int height) +{ + lcd_bitmap_transparent_part(src, 0, 0, + STRIDE(SCREEN_MAIN, width, height), x, y, width, height); +} + +/* draw alpha bitmap for anti-alias font */ +void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x, + int src_y, int stride, int x, int y, + int width, int height) +{ + lcd_alpha_bitmap_part_mix(NULL, src, src_x, src_y, x, y, width, height, 0, stride); +} + +/* Draw a partial bitmap (mono or native) including alpha channel */ +void ICODE_ATTR lcd_bmp_part(const struct bitmap* bm, int src_x, int src_y, + int x, int y, int width, int height) +{ + int bitmap_stride = STRIDE_MAIN(bm->width, bm->height); + if (bm->format == FORMAT_MONO) + lcd_mono_bitmap_part(bm->data, src_x, src_y, bitmap_stride, x, y, width, height); + else if (bm->alpha_offset > 0) + lcd_alpha_bitmap_part_mix((fb_data*)bm->data, bm->data+bm->alpha_offset, + src_x, src_y, x, y, width, height, + bitmap_stride, ALIGN_UP(bm->width, 2)); + else + lcd_bitmap_transparent_part((fb_data*)bm->data, + src_x, src_y, bitmap_stride, x, y, width, height); +} + +/* Draw a native bitmap with alpha channel */ +void ICODE_ATTR lcd_bmp(const struct bitmap *bmp, int x, int y) +{ + lcd_bmp_part(bmp, 0, 0, x, y, bmp->width, bmp->height); +} + +/** + * |R| |1.000000 -0.000001 1.402000| |Y'| + * |G| = |1.000000 -0.334136 -0.714136| |Pb| + * |B| |1.000000 1.772000 0.000000| |Pr| + * Scaled, normalized, rounded and tweaked to yield RGB 565: + * |R| |74 0 101| |Y' - 16| >> 9 + * |G| = |74 -24 -51| |Cb - 128| >> 8 + * |B| |74 128 0| |Cr - 128| >> 9 + */ +#define YFAC (74) +#define RVFAC (101) +#define GUFAC (-24) +#define GVFAC (-51) +#define BUFAC (128) + +static inline int clamp(int val, int min, int max) +{ + if (val < min) + val = min; + else if (val > max) + val = max; + return val; +} + +#ifndef _WIN32 +/* + * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52 + * When building win32 simulators, we won't be using an optimized version of + * lcd_blit_yuv(), so just don't use the weak attribute. + */ +__attribute__((weak)) +#endif +void lcd_yuv_set_options(unsigned options) +{ + (void)options; +} + +/* Draw a partial YUV colour bitmap */ +#ifndef _WIN32 +__attribute__((weak)) +#endif +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + const unsigned char *ysrc, *usrc, *vsrc; + int linecounter; + fb_data *dst, *row_end; + long z; + + /* width and height must be >= 2 and an even number */ + width &= ~1; + linecounter = height >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + dst = FBADDR(x, y); + row_end = dst + width; +#else + dst = FBADDR(LCD_WIDTH - y - 1, x); + row_end = dst + LCD_WIDTH * width; +#endif + + z = stride * src_y; + ysrc = src[0] + z + src_x; + usrc = src[1] + (z >> 2) + (src_x >> 1); + vsrc = src[2] + (usrc - src[1]); + + /* stride => amount to jump from end of last row to start of next */ + stride -= width; + + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + + do + { + do + { + int y, cb, cr, rv, guv, bu, r, g, b; + + y = YFAC*(*ysrc++ - 16); + cb = *usrc++ - 128; + cr = *vsrc++ - 128; + + rv = RVFAC*cr; + guv = GUFAC*cb + GVFAC*cr; + bu = BUFAC*cb; + + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + + y = YFAC*(*ysrc++ - 16); + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + } + while (dst < row_end); + + ysrc += stride; + usrc -= width >> 1; + vsrc -= width >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + row_end += LCD_WIDTH; + dst += LCD_WIDTH - width; +#else + row_end -= 1; + dst -= LCD_WIDTH*width + 1; +#endif + + do + { + int y, cb, cr, rv, guv, bu, r, g, b; + + y = YFAC*(*ysrc++ - 16); + cb = *usrc++ - 128; + cr = *vsrc++ - 128; + + rv = RVFAC*cr; + guv = GUFAC*cb + GVFAC*cr; + bu = BUFAC*cb; + + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + + y = YFAC*(*ysrc++ - 16); + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = FB_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + } + while (dst < row_end); + + ysrc += stride; + usrc += stride >> 1; + vsrc += stride >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + row_end += LCD_WIDTH; + dst += LCD_WIDTH - width; +#else + row_end -= 1; + dst -= LCD_WIDTH*width + 1; +#endif + } + while (--linecounter > 0); + +#if LCD_WIDTH >= LCD_HEIGHT + lcd_update_rect(x, y, width, height); +#else + lcd_update_rect(LCD_WIDTH - y - height, x, height, width); +#endif +} + +/* Fill a rectangle with a gradient. This function draws only the partial + * gradient. It assumes the original gradient is src_height high and skips + * the first few rows. This is useful for drawing only the bottom half of + * a full gradient. + * + * height == src_height and row_skip == 0 will draw the full gradient + * + * x, y, width, height - dimensions describing the rectangle + * start_rgb - beginning color of the gradient + * end_rgb - end color of the gradient + * src_height - assumed original height (only height rows will be drawn) + * row_skip - how many rows of the original gradient to skip + */ +void lcd_gradient_fillrect_part(int x, int y, int width, int height, + unsigned start_rgb, unsigned end_rgb, int src_height, int row_skip) +{ + int old_pattern = current_vp->fg_pattern; + int step_mul, i; + int x1, x2; + x1 = x; + x2 = x + width; + + if (height == 0) return; + + step_mul = (1 << 16) / src_height; + int h_r = RGB_UNPACK_RED(start_rgb); + int h_g = RGB_UNPACK_GREEN(start_rgb); + int h_b = RGB_UNPACK_BLUE(start_rgb); + int rstep = (h_r - RGB_UNPACK_RED(end_rgb)) * step_mul; + int gstep = (h_g - RGB_UNPACK_GREEN(end_rgb)) * step_mul; + int bstep = (h_b - RGB_UNPACK_BLUE(end_rgb)) * step_mul; + h_r = (h_r << 16) + (1 << 15); + h_g = (h_g << 16) + (1 << 15); + h_b = (h_b << 16) + (1 << 15); + + if (row_skip > 0) + { + h_r -= rstep * row_skip; + h_g -= gstep * row_skip; + h_b -= bstep * row_skip; + } + + for(i = y; i < y + height; i++) { + current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16); + lcd_hline(x1, x2, i); + h_r -= rstep; + h_g -= gstep; + h_b -= bstep; + } + + current_vp->fg_pattern = old_pattern; +} + +/* Fill a rectangle with a gradient. The gradient's color will fade from + * start_rgb to end_rgb over the height of the rectangle + * + * x, y, width, height - dimensions describing the rectangle + * start_rgb - beginning color of the gradient + * end_rgb - end color of the gradient + */ +void lcd_gradient_fillrect(int x, int y, int width, int height, + unsigned start_rgb, unsigned end_rgb) +{ + lcd_gradient_fillrect_part(x, y, width, height, start_rgb, end_rgb, height, 0); +} -- cgit v1.2.3