diff --git a/apps/plugin.h b/apps/plugin.h index e16d9ebaec..20e3a71595 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -78,6 +78,7 @@ void* plugin_get_buffer(size_t *buffer_size); #include "playlist.h" #ifdef HAVE_LCD_BITMAP #include "scrollbar.h" +#include "../recorder/bmp.h" #endif #include "statusbar.h" #include "menu.h" diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index 85f4d32f68..fa9e093c3c 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -19,7 +19,6 @@ * ****************************************************************************/ #include "plugin.h" -#include "lib/bmp.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER @@ -258,13 +257,9 @@ static int num_font = FONT_UI; static int moves_font = FONT_UI; static int moves_y = 0; -#ifdef HAVE_LCD_COLOR -static unsigned char *img_buf; -static size_t buf_len; -#else -static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)] -__attribute__ ((aligned(16))); -#endif +static unsigned char img_buf + [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)] + __attribute__ ((aligned(16))); #ifdef HAVE_ALBUMART static char albumart_path[MAX_PATH+1]; #endif @@ -343,13 +338,9 @@ static bool load_resize_bitmap(void) main_bitmap.width = IMAGE_WIDTH; main_bitmap.height = IMAGE_HEIGHT; -#ifndef HAVE_LCD_COLOR - size_t buf_len = sizeof(img_buf); -#endif - rc = rb->read_bmp_file( filename, &main_bitmap, - buf_len, - FORMAT_NATIVE|FORMAT_RESIZE ); + sizeof(img_buf), + FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER); if( rc > 0 ) { puzzle_bmp_ptr = (const fb_data *)img_buf; @@ -574,7 +565,8 @@ static int puzzle_loop(void) /* change picture */ picmode = (picmode+1)%PICMODE_LAST_XXX; - /* if load_resize_bitmap fails to load bitmap, try next picmode */ + /* if load_resize_bitmap fails to load bitmap, try next picmode + */ do { load_success = load_resize_bitmap(); @@ -618,7 +610,8 @@ static int puzzle_loop(void) } } -enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) +enum plugin_status plugin_start(const struct plugin_api* api, + const void* parameter) { int i, w, h; @@ -627,13 +620,6 @@ enum plugin_status plugin_start(const struct plugin_api* api, const void* parame initial_bmp_path=(const char *)parameter; picmode = PICMODE_INITIAL_PICTURE; img_buf_path[0] = '\0'; -#ifdef HAVE_LCD_COLOR - unsigned char *img_buf_end; - img_buf = (unsigned char *)(rb->plugin_get_buffer(&buf_len)); - img_buf_end = img_buf + buf_len; - rb->align_buffer(PUN_PTR(void **,&img_buf), buf_len, 16); - buf_len = img_buf_end - img_buf; -#endif /* If launched as a viewer, just go straight to the game without bothering with the splash or instructions page */ diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index cdff8ccb07..cc574649d8 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c @@ -124,25 +124,10 @@ static const struct uint8_rgb bitfields[3][3] = { }; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) -/* canonical ordered dither matrix */ -const unsigned char dither_matrix[16][16] = { - { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, - { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, - { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, - { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, - { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, - { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, - { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, - { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, - { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, - { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, - { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, - { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, - { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, - { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, - { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, - { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } -}; +/* the full 16x16 Bayer dither matrix may be calculated quickly with this table +*/ +const unsigned char dither_table[16] = + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }; #endif #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ @@ -194,7 +179,7 @@ struct bmp_args { short read_width; short width; short depth; - unsigned char buf[MAX_WIDTH * 4]; + unsigned char buf[BM_MAX_WIDTH * 4]; struct uint8_rgb *palette; #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) int cur_row; @@ -222,13 +207,14 @@ static unsigned int read_part_line(struct bmp_args *ba) int i, cols, len; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - cols = MIN(width - cur_col,(int)MAX_WIDTH); + cols = MIN(width - cur_col,(int)BM_MAX_WIDTH); + BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH); len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3; #else cols = width; len = read_width; #endif - ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len; + ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len; BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len); ret = read(fd, ibuf, len); if (ret != len) @@ -239,25 +225,25 @@ static unsigned int read_part_line(struct bmp_args *ba) cols, len); return 0; } - for (i = 0; i < cols; i++) + while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) { switch (depth) { case 1: - if ((i & 7) == 0) - data = *ibuf++; - *buf = palette[(data >> 7) & 1]; - data <<= 1; + data = *ibuf++; + for (i = 0; i < 8; i++) + { + *buf++ = palette[data & 0x80 ? 1 : 0]; + data <<= 1; + } break; case 4: - *buf = palette[*ibuf >> 4]; - if (i & 1) - ibuf++; - else - *ibuf <<= 4; + data = *ibuf++; + *buf++ = palette[data >> 4]; + *buf++ = palette[data & 0xf]; break; case 8: - *buf = palette[*ibuf++]; + *buf++ = palette[*ibuf++]; break; case 15: case 16: @@ -280,6 +266,7 @@ static unsigned int read_part_line(struct bmp_args *ba) component = data & 0xf8; component |= component >> 5; buf->red = component; + buf++; ibuf += 2; break; case 32: @@ -289,11 +276,19 @@ static unsigned int read_part_line(struct bmp_args *ba) buf->red = *ibuf++; if (depth == 32) ibuf++; + buf++; break; } - buf++; } +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + ibuf = ba->buf; + buf = (struct uint8_rgb*)ba->buf; + while (ibuf < ba->buf + cols) + *ibuf++ = brightness(*buf++); +#endif + #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) cur_col += cols; if (cur_col == width) @@ -323,58 +318,16 @@ static struct img_part *store_part_bmp(void *args) struct bmp_args *ba = (struct bmp_args *)args; ba->part.len = read_part_line(ba); +#ifdef HAVE_LCD_COLOR ba->part.buf = (struct uint8_rgb *)ba->buf; +#else + ba->part.buf = (uint8_t *)ba->buf; +#endif if (ba->part.len) return &(ba->part); else return NULL; } - -static bool skip_lines_bmp(void *args, unsigned int lines) -{ - struct bmp_args * ba = (struct bmp_args *)args; - - int pad = lines * ba->padded_width + - (ba->cur_col - ? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width - : 0); - if (pad) - { - if(lseek(ba->fd, pad, SEEK_CUR) < 0) - - return false; - } - ba->cur_row += lines + (ba->cur_col ? 1 : 0); - ba->cur_col = 0; - return true; -} -#endif - -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -static inline int recalc_dimension(struct dim *dst, struct dim *src) -{ - int tmp; - if (dst->width <= 0) - dst->width = LCD_WIDTH; - if (dst->height <= 0) - dst->height = LCD_HEIGHT; -#ifndef HAVE_UPSCALER - if (dst->width > src->width || dst->height > src->height) - { - dst->width = src->width; - dst->height = src->height; - } - if (src->width == dst->width && src->height == dst->height) - return 1; -#endif - tmp = (src->width * dst->height + (src->height >> 1)) / src->height; - if (tmp > dst->width) - dst->height = (src->height * dst->width + (src->width >> 1)) - / src->width; - else - dst->width = tmp; - return src->width == dst->width && src->height == dst->height; -} #endif static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) @@ -406,37 +359,32 @@ int read_bmp_fd(int fd, unsigned char *bitmap = bm->data; struct uint8_rgb palette[256]; - bool remote = false; struct rowset rset; struct dim src_dim; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + bool remote = false; unsigned int resize = IMG_NORESIZE; bool dither = false; bool transparent = false; - + #ifdef HAVE_REMOTE_LCD if (format & FORMAT_REMOTE) { remote = true; #if LCD_REMOTE_DEPTH == 1 format = FORMAT_MONO; -#else - format &= ~FORMAT_REMOTE; #endif } #endif /* HAVE_REMOTE_LCD */ if (format & FORMAT_RESIZE) { resize = IMG_RESIZE; - format &= ~FORMAT_RESIZE; } if (format & FORMAT_TRANSPARENT) { transparent = true; - format &= ~FORMAT_TRANSPARENT; } if (format & FORMAT_DITHER) { dither = true; - format &= ~FORMAT_DITHER; } #else @@ -470,23 +418,23 @@ int read_bmp_fd(int fd, BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width, src_dim.height, depth, padded_width); - -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + +#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) if ((format & 3) == FORMAT_ANY) { if (depth == 1) format = (format & ~3); else format = (format & ~3) | FORMAT_NATIVE; } - bm->format = format & 3; - if ((format & 3) == FORMAT_MONO) + bm->format = format & 1; + if ((format & 1) == FORMAT_MONO) { resize &= ~IMG_RESIZE; resize |= IMG_NORESIZE; remote = 0; } #else - if (src_dim.width > MAX_WIDTH) + if (src_dim.width > BM_MAX_WIDTH) return -6; #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ @@ -494,7 +442,6 @@ int read_bmp_fd(int fd, if (resize & IMG_RESIZE) { if(format & FORMAT_KEEP_ASPECT) { /* keep aspect ratio.. */ - format &= ~FORMAT_KEEP_ASPECT; struct dim resize_dim = { .width = bm->width, .height = bm->height, @@ -506,6 +453,8 @@ int read_bmp_fd(int fd, } } + format &= 1; + if (!(resize & IMG_RESIZE)) { #endif /* returning image size */ @@ -524,7 +473,7 @@ int read_bmp_fd(int fd, rset.rowstop = -1; } - totalsize = get_totalsize(bm, remote); + totalsize = BM_SIZE(bm->width,bm->height,format,remote); /* Check if this fits the buffer */ if (totalsize > maxsize) { @@ -616,90 +565,146 @@ int read_bmp_fd(int fd, }; #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -#if LCD_DEPTH == 16 -#ifdef HAVE_REMOTE_LCD - if (resize & IMG_RESIZE || remote) -#else - if (resize & IMG_RESIZE) -#endif -#else - if (format == FORMAT_NATIVE) -#endif - return resize_on_load(bm, dither, &src_dim, &rset, remote, -#ifdef HAVE_LCD_COLOR + if (resize) + return resize_on_load(bm, dither, &src_dim, &rset, bitmap + totalsize, maxsize - totalsize, -#endif - store_part_bmp, skip_lines_bmp, &ba); + store_part_bmp, &ba); + + int fb_width = BM_WIDTH(bm->width,bm->format,remote); #endif /* LCD_DEPTH */ - int fb_width = get_fb_width(bm, remote); int col, row; /* loop to read rows and put them to buffer */ for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { - struct uint8_rgb *qp; +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + uint8_t* qp = ba.buf; +#else + struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf; +#endif unsigned mask; unsigned char *p; -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - unsigned int len; - - if (!(len = read_part_line(&ba))) - return -9; -#else if (!read_part_line(&ba)) return -9; -#endif /* Convert to destination format */ - qp = (struct uint8_rgb *) ba.buf; -#if LCD_DEPTH == 16 - if (format == FORMAT_NATIVE) - { - /* iriver h300, colour iPods, X5 */ - fb_data *dest = (fb_data *)bitmap + fb_width * row; - int delta = 127; - unsigned r, g, b; - struct uint8_rgb q0; +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + unsigned char dy = DITHERY(row); + if (format == FORMAT_NATIVE) { +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) { +#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) + /* iAudio X5/M5 remote */ + fb_remote_data *dest = (fb_remote_data *)bitmap + + bm->width * (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; - for (col = 0; col < src_dim.width; col++) { - if (dither) - delta = dither_mat(row & 0xf, col & 0xf); - if (!len) - { - if(!(len = read_part_line(&ba))) - return -9; - else - qp = (struct uint8_rgb *)ba.buf; - } - q0 = *qp++; - len--; - r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; - g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; - b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; - *dest++ = LCD_RGBPACK_LCD(r, g, b); - } - } - else + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + bright = *qp++; +#else + bright = brightness(*qp++); #endif - { - p = bitmap + fb_width * (row >> 3); - mask = 1 << (row & 7); - for (col = 0; col < src_dim.width; col++) + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ { -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) - if (!len) - { - if(!(len = read_part_line(&ba))) - return -9; - else - qp = (struct uint8_rgb *)ba.buf; +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + /* greyscale iPods */ + fb_data *dest = (fb_data *)bitmap + fb_width * row; + int shift = 6; + int delta = 127; + unsigned bright; + unsigned data = 0; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + data |= (~bright & 3) << shift; + shift -= 2; + if (shift < 0) { + *dest++ = data; + data = 0; + shift = 6; + } } - len--; -#endif + if (shift < 6) + *dest++ = data; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 2); + int shift = 2 * (row & 3); + int delta = 127; + unsigned bright; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= (~bright & 3) << shift; + } +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + /* iAudio M3 */ + fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + bright = *qp++; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + /* iriver h300, colour iPods, X5 */ + fb_data *dest = (fb_data *)bitmap + fb_width * row; + int delta = 127; + unsigned r, g, b; + struct uint8_rgb q0; + + for (col = 0; col < bm->width; col++) { + if (dither) + delta = DITHERXDY(col,dy); + q0 = *qp++; + r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; + g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; + b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } +#endif /* LCD_DEPTH */ + } + } else +#endif /* (LCD_DEPTH > 1) || + defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + p = bitmap + bm->width * (row >> 3); + mask = 1 << (row & 7); + + for (col = 0; col < bm->width; col++, p++) +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + if (*qp++ < 128) + *p |= mask; +#else if (brightness(*qp++) < 128) *p |= mask; - p++; - } +#endif } } return totalsize; /* return the used buffer size. */ diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index d1b1d7f3ed..273e178bc9 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h @@ -32,11 +32,7 @@ #define IMG_NORESIZE 0 #define IMG_RESIZE 1 -#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) -#define MAX_WIDTH 8 -#else -#define MAX_WIDTH LCD_WIDTH -#endif +#define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7) struct uint8_rgb { uint8_t blue; @@ -56,129 +52,144 @@ struct rowset { }; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) -extern const unsigned char dither_matrix[16][16]; -static inline unsigned char dither_mat(unsigned int x, unsigned int y) -{ - return dither_matrix[y][x]; -} +extern const unsigned char dither_table[16]; +#define DITHERY(y) (dither_table[(y) & 15] & 0xAA) +#define DITHERX(x) (dither_table[(x) & 15]) +#define DITHERXDY(x,dy) (DITHERX(x) ^ dy) +#define DITHERDXY(dx,y) (dx ^ DITHERY(y)) +#define DITHERXY(x,y) (DITHERX(x) ^ DITHERY(y)) #endif +/* The /256 version has a mean squared variance from YUV luma of <1 grey level. + The /8 version is a good deal less accurate, but sufficient on mono as we + don't support HQ output or dithering there, yet. +*/ static inline unsigned brightness(struct uint8_rgb color) { - return (3 * (unsigned)color.red + 6 * (unsigned)color.green - + (unsigned)color.blue) / 10; +#if LCD_DEPTH > 1 + return (77 * (unsigned)color.red + 150 * (unsigned)color.green + + 29 * (unsigned)color.blue) / 256; +#else + return (2 * (unsigned)color.red + 5 * (unsigned)color.green + + (unsigned)color.blue) / 8; +#endif } #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) extern const unsigned short vi_pattern[4]; -static inline unsigned short vi_pat(unsigned int bright) -{ - return vi_pattern[bright]; -} #endif -static inline int get_fb_height(struct bitmap *bm, bool remote) -{ - const int height = bm->height; -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - const int format = bm->format; -#endif - int dst_height; +/* Number of rows of data in a mono bitmap height pixels tall */ +#define MONO_BM_HEIGHT(height) (((height) + 7) >> 3) -#if !defined(HAVE_REMOTE_LCD) || \ - (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) - (void) remote; +/* Number of rows of datain a LCD native bitmap height pixels tall */ +#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) +#if LCD_DEPTH == 1 || \ + (LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) +#define LCD_BM_HEIGHT(height) (((height) + 7) >> 3) +#elif LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_PACKING +#define LCD_BM_HEIGHT(height) (((height) + 3) >> 2) +#else +#define LCD_BM_HEIGHT(height) (height) #endif -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - if (format == FORMAT_NATIVE) { -#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - if (remote) { -#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) - dst_height = (height + 7) >> 3; -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - } else -#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ - { -#if LCD_DEPTH == 2 -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dst_height = height; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dst_height = (height + 3) >> 2; -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dst_height = (height + 7) >> 3; -#endif /* LCD_PIXELFORMAT */ -#elif LCD_DEPTH == 16 - dst_height = height; -#endif /* LCD_DEPTH */ - } - } else -#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - { - dst_height = (height + 7) >> 3; - } - - return dst_height; -} - -static inline int get_fb_width(struct bitmap *bm, bool remote) -{ - const int width = bm->width; -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - const int format = bm->format; -#endif - int dst_width; - -#if !defined(HAVE_REMOTE_LCD) || \ - (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) - (void) remote; -#endif - -#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) - if (format == FORMAT_NATIVE) { -#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 - if (remote) { -#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) - dst_width = width; -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - } else -#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ - { -#if LCD_DEPTH == 2 -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dst_width = (width + 3) >> 2; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dst_width = width; -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dst_width = width; -#endif /* LCD_PIXELFORMAT */ -#elif LCD_DEPTH == 16 - dst_width = width; -#endif /* LCD_DEPTH */ - } - } else -#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ - { - dst_width = width; - } - - return dst_width; -} - -static inline int get_totalsize(struct bitmap *bm, bool remote) -{ - int sz; +/* Number of rows of data in a remote native bitmap height pixels tall. */ #ifdef HAVE_REMOTE_LCD - if (remote && sizeof(fb_data) != sizeof(fb_remote_data)) - sz = sizeof(fb_remote_data); - else -#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ - sz = sizeof(fb_data); +#if LCD_REMOTE_DEPTH == 1 || \ + (LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) +#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 7) >> 3) +#elif LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING +#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 3) >> 2) +#else +#define LCD_REMOTE_BM_HEIGHT(height) (height) +#endif +#define NATIVE_BM_HEIGHT(height,remote) ((remote) ? \ + LCD_REMOTE_BM_HEIGHT(height) : LCD_BM_HEIGHT(height)) +#else +#define NATIVE_BM_HEIGHT(height,remote) LCD_BM_HEIGHT(height) +#endif - return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; -} +/* Convenience macro to calculate rows based on height, remote vs main LCD, + and format +*/ +#define BM_HEIGHT(height,format,remote) ((format) == FORMAT_MONO ? \ + MONO_BM_HEIGHT(height) : NATIVE_BM_HEIGHT(height,remote)) +#else +#define BM_HEIGHT(height,format,remote) MONO_BM_HEIGHT(height) +#endif + +/* Number of data elements in a mono bitmap width pixels wide */ +#define MONO_BM_WIDTH(width) (width) + +/* Number of data elements in a LCD native bitmap width pixels wide */ +#if LCD_DEPTH > 1 +#if LCD_DEPTH == 2 && LCD_PIXELFORMAT == HORIZONTAL_PACKING +#define LCD_BM_WIDTH(width) (((width) + 3) >> 2) +#else +#define LCD_BM_WIDTH(width) (width) +#endif + +/* Number of data elements in a remote native bitmap width pixels wide */ +#ifdef HAVE_LCD_REMOTE +#if LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING +#define LCD_REMOTE_BM_WIDTH(width) (((width) + 3) >> 2) +#else +#define LCD_REMOTE_BM_WIDTH(width) (width) +#endif +#define NATIVE_BM_WIDTH(width,remote) ((remote) ? \ + LCD_REMOTE_BM_WIDTH(width) : LCD_BM_WIDTH(width)) +#else +#define NATIVE_BM_WIDTH(width,remote) LCD_BM_WIDTH(width) +#endif + +/* Convenience macro to calculate elements based on height, remote vs native + main LCD, and format +*/ +#define BM_WIDTH(width,format,remote) ((format) == FORMAT_MONO ? \ + MONO_BM_WIDTH(width) : NATIVE_BM_WIDTH(width,remote)) +#else +#define BM_WIDTH(width,format,remote) MONO_BM_WIDTH(width) +#endif + +/* Size in bytes of a mono bitmap of dimensions width*height */ +#define MONO_BM_SIZE(width,height) (MONO_BM_WIDTH(width) * \ + MONO_BM_HEIGHT(height) * FB_DATA_SZ) + +/* Size in bytes of a native bitmap of dimensions width*height */ +#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) +#if defined(HAVE_REMOTE_LCD) && FB_DATA_SZ != FB_RDATA_SZ +#define NATIVE_BM_SIZE(width,height,format,remote) \ + (((remote) ? FB_RDATA_SZ : FB_DATA_SZ) * BM_WIDTH(width,format,remote) \ + * BM_HEIGHT(height,format,remote)) +#else +#define NATIVE_BM_SIZE(width,height,format,remote) \ + (FB_DATA_SZ * BM_WIDTH(width,format,remote) * \ + BM_HEIGHT(height,format,remote)) +#endif + +/* Convenience macro to calculate size in bytes based on height, remote vs + main LCD, and format +*/ +#define BM_SIZE(width,height,format,remote) (((format) == FORMAT_MONO) ? \ + MONO_BM_SIZE(width,height) : NATIVE_BM_SIZE(width,height,format,remote)) +#else +#define BM_SIZE(width,height,format,remote) MONO_BM_SIZE(width,height) +#endif + +/* Size in bytes needed to load and scale a bitmap with target size up to + width*height, including overhead to allow for buffer alignment. +*/ +#ifdef HAVE_LCD_COLOR +#define BM_SCALED_SIZE(width,height,format,remote) \ + (BM_SIZE(width,height,format,remote) + \ + (remote ? 0 : BM_WIDTH(width,format,remote) * sizeof(uint32_t) * 9 + 3)) +#else +#define BM_SCALED_SIZE(width,height,format,remote) \ + (BM_SIZE(width,height,format,remote) + \ + (width * sizeof(uint32_t) * 3 + 3)) +#endif /********************************************************************* * read_bmp_file() diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c index e41501032a..3c1d34f046 100644 --- a/apps/recorder/resize.c +++ b/apps/recorder/resize.c @@ -59,15 +59,45 @@ #define DEBUGF(...) #endif +/* calculate the maximum dimensions which will preserve the aspect ration of + src while fitting in the constraints passed in dst, and store result in dst, + returning 0 if rounding and 1 if not rounding. +*/ +int recalc_dimension(struct dim *dst, struct dim *src) +{ + int tmp; + if (dst->width <= 0) + dst->width = LCD_WIDTH; + if (dst->height <= 0) + dst->height = LCD_HEIGHT; +#ifndef HAVE_UPSCALER + if (dst->width > src->width || dst->height > src->height) + { + dst->width = src->width; + dst->height = src->height; + } + if (src->width == dst->width && src->height == dst->height) + return 1; +#endif + tmp = (src->width * dst->height + (src->height >> 1)) / src->height; + if (tmp > dst->width) + dst->height = (src->height * dst->width + (src->width >> 1)) + / src->width; + else + dst->width = tmp; + return src->width == dst->width && src->height == dst->height; +} + /* All of these scalers use variations of Bresenham's algorithm to convert from - their input to output coordinates. The color scalers have the error value - shifted so that it is a useful input to the scaling algorithm. + their input to output coordinates. The error value is shifted from the + "classic" version such that it is a useful input to the scaling calculation. */ #ifdef HAVE_LCD_COLOR /* dither + pack on channel of RGB565, R an B share a packing macro */ #define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) #define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) +#endif /* read new img_part unconditionally, return false on failure */ #define FILL_BUF_INIT(img_part, store_part, args) { \ @@ -84,183 +114,204 @@ return false; \ } -struct uint32_rgb { - uint32_t r; - uint32_t g; - uint32_t b; -}; - +/* struct which containers various parameters shared between vertical scaler, + horizontal scaler, and row output +*/ struct scaler_context { - uint32_t divmul; + uint32_t divisor; uint32_t round; - struct img_part* (*store_part)(void *); - long last_tick; + struct bitmap *bm; + struct dim *src; unsigned char *buf; + bool dither; int len; void *args; + struct img_part* (*store_part)(void *); + void (*output_row)(uint32_t,void*,struct scaler_context*); + bool (*h_scaler)(void*,struct scaler_context*, bool); }; /* Set up rounding and scale factors for horizontal area scaler */ -static void scale_h_area_setup(struct bitmap *bm, struct dim *src, - struct scaler_context *ctx) +static inline void scale_h_area_setup(struct scaler_context *ctx) { - (void) bm; /* sum is output value * src->width */ - ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1; - ctx->round = (src->width + 1) >> 1; + SDEBUGF("scale_h_area_setup\n"); + ctx->divisor = ctx->src->width; } /* horizontal area average scaler */ -static bool scale_h_area(struct bitmap *bm, struct dim *src, - struct uint32_rgb *out_line, +static bool scale_h_area(void *out_line_ptr, struct scaler_context *ctx, bool accum) { SDEBUGF("scale_h_area\n"); unsigned int ix, ox, oxe, mul; - struct uint32_rgb rgbvalacc = { 0, 0, 0 }, - rgbvaltmp = { 0, 0, 0 }; +#ifdef HAVE_LCD_COLOR + struct uint32_rgb rgbvalacc = { 0, 0, 0 }, + rgbvaltmp = { 0, 0, 0 }, + *out_line = (struct uint32_rgb *)out_line_ptr; +#else + uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr; +#endif struct img_part *part; FILL_BUF_INIT(part,ctx->store_part,ctx->args); ox = 0; oxe = 0; mul = 0; - for (ix = 0; ix < (unsigned int)src->width; ix++) + /* give other tasks a chance to run */ + yield(); + for (ix = 0; ix < (unsigned int)ctx->src->width; ix++) { - oxe += bm->width; + oxe += ctx->bm->width; /* end of current area has been reached */ - if (oxe >= (unsigned int)src->width) + /* fill buffer if needed */ + FILL_BUF(part,ctx->store_part,ctx->args); +#ifdef HAVE_LCD_COLOR + if (oxe >= (unsigned int)ctx->src->width) { - /* yield if we haven't since last tick */ - if (ctx->last_tick != current_tick) - { - yield(); - ctx->last_tick = current_tick; - } /* "reset" error, which now represents partial coverage of next pixel by the next area */ - oxe -= src->width; + oxe -= ctx->src->width; + /* add saved partial pixel from start of area */ - rgbvalacc.r = rgbvalacc.r * bm->width + rgbvaltmp.r * mul; - rgbvalacc.g = rgbvalacc.g * bm->width + rgbvaltmp.g * mul; - rgbvalacc.b = rgbvalacc.b * bm->width + rgbvaltmp.b * mul; - /* fill buffer if needed */ - FILL_BUF(part,ctx->store_part,ctx->args); + rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul; + rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul; + rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul; + /* get new pixel , then add its partial coverage to this area */ rgbvaltmp.r = part->buf->red; rgbvaltmp.g = part->buf->green; rgbvaltmp.b = part->buf->blue; - part->buf++; - part->len--; - mul = bm->width - oxe; + mul = ctx->bm->width - oxe; rgbvalacc.r += rgbvaltmp.r * mul; rgbvalacc.g += rgbvaltmp.g * mul; rgbvalacc.b += rgbvaltmp.b * mul; - /* round, divide, and either store or accumulate to output row */ - out_line[ox].r = (accum ? out_line[ox].r : 0) + - ((rgbvalacc.r + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].g = (accum ? out_line[ox].g : 0) + - ((rgbvalacc.g + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].b = (accum ? out_line[ox].b : 0) + - ((rgbvalacc.b + ctx->round) * - (uint64_t)ctx->divmul >> 32); + /* store or accumulate to output row */ + if (accum) + { + rgbvalacc.r += out_line[ox].r; + rgbvalacc.g += out_line[ox].g; + rgbvalacc.b += out_line[ox].b; + } + out_line[ox].r = rgbvalacc.r; + out_line[ox].g = rgbvalacc.g; + out_line[ox].b = rgbvalacc.b; /* reset accumulator */ rgbvalacc.r = 0; rgbvalacc.g = 0; rgbvalacc.b = 0; - mul = bm->width - mul; + mul = ctx->bm->width - mul; ox += 1; /* inside an area */ } else { - /* fill buffer if needed */ - FILL_BUF(part,ctx->store_part,ctx->args); /* add pixel value to accumulator */ rgbvalacc.r += part->buf->red; rgbvalacc.g += part->buf->green; rgbvalacc.b += part->buf->blue; - part->buf++; - part->len--; } +#else + if (oxe >= (unsigned int)ctx->src->width) + { + /* "reset" error, which now represents partial coverage of next + pixel by the next area + */ + oxe -= ctx->src->width; + + /* add saved partial pixel from start of area */ + acc = acc * ctx->bm->width + tmp * mul; + + /* get new pixel , then add its partial coverage to this area */ + tmp = *(part->buf); + mul = ctx->bm->width - oxe; + acc += tmp * mul; + /* round, divide, and either store or accumulate to output row */ + if (accum) + { + acc += out_line[ox]; + } + out_line[ox] = acc; + /* reset accumulator */ + acc = 0; + mul = ctx->bm->width - mul; + ox += 1; + /* inside an area */ + } else { + /* add pixel value to accumulator */ + acc += *(part->buf); + } +#endif + part->buf++; + part->len--; } return true; } /* vertical area average scaler */ -static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool), - struct scaler_context *ctx) +static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx) { - uint32_t mul, divmul, x, oy, iy, oye, round; - int delta = 127, r, g, b; - fb_data *row, *pix; + uint32_t mul, x, oy, iy, oye; /* Set up rounding and scale factors */ - divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1; - round = (src->height + 1) >> 1; + ctx->divisor *= ctx->src->height; + ctx->round = ctx->divisor >> 1; + ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1; mul = 0; - oy = 0; + oy = rset->rowstart; oye = 0; - struct uint32_rgb *rowacc = (struct uint32_rgb *)(ctx->buf), - *rowtmp = rowacc + bm->width; - +#ifdef HAVE_LCD_COLOR + uint32_t *rowacc = (uint32_t *) ctx->buf, + *rowtmp = rowacc + 3 * ctx->bm->width; + memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb)); +#else + uint32_t *rowacc = (uint32_t *) ctx->buf, + *rowtmp = rowacc + ctx->bm->width; + memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t)); +#endif SDEBUGF("scale_v_area\n"); /* zero the accumulator and temp rows */ - memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb)); - row = (fb_data *)(bm->data) + bm->width * rset->rowstart; - for (iy = 0; iy < (unsigned int)src->height; iy++) + for (iy = 0; iy < (unsigned int)ctx->src->height; iy++) { - oye += bm->height; + oye += ctx->bm->height; /* end of current area has been reached */ - if (oye >= (unsigned int)src->height) + if (oye >= (unsigned int)ctx->src->height) { /* "reset" error, which now represents partial coverage of the next row by the next area */ - oye -= src->height; + oye -= ctx->src->height; /* add stored partial row to accumulator */ - for (x = 0; x < 3 *(unsigned int)bm->width; x++) - ((uint32_t*)rowacc)[x] = ((uint32_t*)rowacc)[x] * - bm->height + mul * - ((uint32_t*)rowtmp)[x]; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) +#else + for (x = 0; x < (unsigned int)ctx->bm->width; x++) +#endif + rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x]; /* store new scaled row in temp row */ - if(!h_scaler(bm, src, rowtmp, ctx, false)) + if(!ctx->h_scaler(rowtmp, ctx, false)) return false; /* add partial coverage by new row to this area, then round and scale to final value */ - mul = bm->height - oye; - for (x = 0; x < 3 *(unsigned int)bm->width; x++) - { - ((uint32_t*)rowacc)[x] += mul * ((uint32_t*)rowtmp)[x]; - ((uint32_t*)rowacc)[x] = (round + - ((uint32_t*)rowacc)[x]) * - (uint64_t)divmul >> 32; - } - /* convert to RGB565 in output bitmap */ - pix = row; - for (x = 0; x < (unsigned int)bm->width; x++) - { - if (dither) - delta = dither_mat(x & 0xf, oy & 0xf); - r = PACKRB(rowacc[x].r,delta); - g = PACKG(rowacc[x].g,delta); - b = PACKRB(rowacc[x].b,delta); - *pix++ = LCD_RGBPACK_LCD(r, g, b); - } + mul = ctx->bm->height - oye; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++) +#else + for (x = 0; x < (unsigned int)ctx->bm->width; x++) +#endif + rowacc[x] += mul * rowtmp[x]; + ctx->output_row(oy, (void*)rowacc, ctx); /* clear accumulator row, store partial coverage for next row */ - memset((void *)rowacc, 0, bm->width * sizeof(struct uint32_rgb)); +#ifdef HAVE_LCD_COLOR + memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3); +#else + memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t)); +#endif mul = oye; - row += bm->width * rset->rowstep; - oy += 1; + oy += rset->rowstep; /* inside an area */ } else { /* accumulate new scaled row to rowacc */ - if (!h_scaler(bm, src, rowacc, ctx, true)) + if (!ctx->h_scaler(rowacc, ctx, true)) return false; } } @@ -272,53 +323,52 @@ static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, is bm->width - 1, so that the first and last pixels in the row align exactly between input and output */ -static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, - struct scaler_context *ctx) +static inline void scale_h_linear_setup(struct scaler_context *ctx) { - (void) src; - ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1; - ctx->round = bm->width >> 1; + ctx->divisor = ctx->bm->width - 1; } /* horizontal linear scaler */ -static bool scale_h_linear(struct bitmap *bm, struct dim *src, - struct uint32_rgb *out_line, - struct scaler_context *ctx, bool accum) +static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx, + bool accum) { unsigned int ix, ox, ixe; /* type x = x is an ugly hack for hiding an unitialized data warning. The values are conditionally initialized before use, but other values are set such that this will occur before these are used. */ - struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc; +#ifdef HAVE_LCD_COLOR + struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc, + *out_line = (struct uint32_rgb*)out_line_ptr; +#else + uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr; +#endif struct img_part *part; SDEBUGF("scale_h_linear\n"); FILL_BUF_INIT(part,ctx->store_part,ctx->args); ix = 0; /* The error is set so that values are initialized on the first pass. */ - ixe = bm->width - 1; - for (ox = 0; ox < (uint32_t)bm->width; ox++) { - if (ixe >= ((uint32_t)bm->width - 1)) + ixe = ctx->bm->width - 1; + /* give other tasks a chance to run */ + yield(); + for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++) + { +#ifdef HAVE_LCD_COLOR + if (ixe >= ((uint32_t)ctx->bm->width - 1)) { - /* yield once each tick */ - if (ctx->last_tick != current_tick) - { - yield(); - ctx->last_tick = current_tick; - } - /* Store the new "current" pixel value in rgbval, and the color + /* Store the new "current" pixel value in rgbval, and the color step value in rgbinc. */ - ixe -= (bm->width - 1); + ixe -= (ctx->bm->width - 1); rgbinc.r = -(part->buf->red); rgbinc.g = -(part->buf->green); rgbinc.b = -(part->buf->blue); - rgbval.r = (part->buf->red) * (bm->width - 1); - rgbval.g = (part->buf->green) * (bm->width - 1); - rgbval.b = (part->buf->blue) * (bm->width - 1); + rgbval.r = (part->buf->red) * (ctx->bm->width - 1); + rgbval.g = (part->buf->green) * (ctx->bm->width - 1); + rgbval.b = (part->buf->blue) * (ctx->bm->width - 1); ix += 1; /* If this wasn't the last pixel, add the next one to rgbinc. */ - if (ix < (uint32_t)src->width) { + if (ix < (uint32_t)ctx->src->width) { part->buf++; part->len--; /* Fetch new pixels if needed */ @@ -334,448 +384,314 @@ static bool scale_h_linear(struct bitmap *bm, struct dim *src, rgbval.b += rgbinc.b * ixe; } /* Now multiple the color increment to its proper value */ - rgbinc.r *= src->width - 1; - rgbinc.g *= src->width - 1; - rgbinc.b *= src->width - 1; + rgbinc.r *= ctx->src->width - 1; + rgbinc.g *= ctx->src->width - 1; + rgbinc.b *= ctx->src->width - 1; + } else { + rgbval.r += rgbinc.r; + rgbval.g += rgbinc.g; + rgbval.b += rgbinc.b; } /* round and scale values, and accumulate or store to output */ - out_line[ox].r = (accum ? out_line[ox].r : 0) + - ((rgbval.r + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].g = (accum ? out_line[ox].g : 0) + - ((rgbval.g + ctx->round) * - (uint64_t)ctx->divmul >> 32); - out_line[ox].b = (accum ? out_line[ox].b : 0) + - ((rgbval.b + ctx->round) * - (uint64_t)ctx->divmul >> 32); - rgbval.r += rgbinc.r; - rgbval.g += rgbinc.g; - rgbval.b += rgbinc.b; - ixe += src->width - 1; + if (accum) + { + out_line[ox].r += rgbval.r; + out_line[ox].g += rgbval.g; + out_line[ox].b += rgbval.b; + } else { + out_line[ox].r = rgbval.r; + out_line[ox].g = rgbval.g; + out_line[ox].b = rgbval.b; + } +#else + if (ixe >= ((uint32_t)ctx->bm->width - 1)) + { + /* Store the new "current" pixel value in rgbval, and the color + step value in rgbinc. + */ + ixe -= (ctx->bm->width - 1); + val = *(part->buf); + inc = -val; + val *= (ctx->bm->width - 1); + ix += 1; + /* If this wasn't the last pixel, add the next one to rgbinc. */ + if (ix < (uint32_t)ctx->src->width) { + part->buf++; + part->len--; + /* Fetch new pixels if needed */ + FILL_BUF(part,ctx->store_part,ctx->args); + inc += *(part->buf); + /* Add a partial step to rgbval, in this pixel isn't precisely + aligned with the new source pixel + */ + val += inc * ixe; + } + /* Now multiply the color increment to its proper value */ + inc *= ctx->src->width - 1; + } else + val += inc; + /* round and scale values, and accumulate or store to output */ + if (accum) + { + out_line[ox] += val; + } else { + out_line[ox] = val; + } +#endif + ixe += ctx->src->width - 1; } return true; } /* vertical linear scaler */ -static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool), - struct scaler_context *ctx) +static inline bool scale_v_linear(struct rowset *rset, + struct scaler_context *ctx) { - uint32_t mul, divmul, x, oy, iy, iye, round; - int delta = 127; - struct uint32_rgb p; - fb_data *row, *pix; + uint32_t mul, x, iy, iye; + int32_t oy; /* Set up scale and rounding factors, the divisor is bm->height - 1 */ - divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1; - round = bm->height >> 1; - mul = 0; - iy = 0; - iye = bm->height - 1; + ctx->divisor *= (ctx->bm->height - 1); + ctx->round = ctx->divisor >> 1; + ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1; /* Set up our two temp buffers. The names are generic because they'll be swapped each time a new input row is read */ - struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), - *crow2 = crow1 + bm->width, - *t; +#ifdef HAVE_LCD_COLOR + uint32_t *rowinc = (uint32_t *)(ctx->buf), + *rowval = rowinc + 3 * ctx->bm->width, + *rowtmp = rowval + 3 * ctx->bm->width; +#else + uint32_t *rowinc = (uint32_t *)(ctx->buf), + *rowval = rowinc + ctx->bm->width, + *rowtmp = rowval + ctx->bm->width; +#endif SDEBUGF("scale_v_linear\n"); - row = (fb_data *)(bm->data) + bm->width * rset->rowstart; - /* get first scaled row in crow2 */ - if(!h_scaler(bm, src, crow2, ctx, false)) + mul = 0; + iy = 0; + iye = ctx->bm->height - 1; + /* get first scaled row in rowtmp */ + if(!ctx->h_scaler((void*)rowtmp, ctx, false)) return false; - for (oy = 0; oy < (uint32_t)bm->height; oy++) + for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep) { - if (iye >= (uint32_t)bm->height - 1) + if (iye >= (uint32_t)ctx->bm->height - 1) { - /* swap temp rows, then read another row into crow2 */ - t = crow2; - crow2 = crow1; - crow1 = t; - iye -= bm->height - 1; + iye -= ctx->bm->height - 1; iy += 1; - if (iy < (uint32_t)src->height) +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif { - if (!h_scaler(bm, src, crow2, ctx, false)) - return false; + rowinc[x] = -rowtmp[x]; + rowval[x] = rowtmp[x] * (ctx->bm->height - 1); } - } - pix = row; - for (x = 0; x < (uint32_t)bm->width; x++) - { - /* iye and bm-height - 1 - iye represent the contribution of each - row to the output. Calculate their weighted sum, then round and - scale it. - */ - p.r = (crow1[x].r * (bm->height - 1 - iye) + - crow2[x].r * iye + round) * (uint64_t)divmul >> 32; - p.g = (crow1[x].g * (bm->height - 1 - iye) + - crow2[x].g * iye + round) * (uint64_t)divmul >> 32; - p.b = (crow1[x].b * (bm->height - 1 - iye) + - crow2[x].b * iye + round) * (uint64_t)divmul >> 32; - /* dither and pack pixels to output */ - if (dither) - delta = dither_mat(x & 0xf, oy & 0xf); - p.r = PACKRB(p.r,delta); - p.g = PACKG(p.g,delta); - p.b = PACKRB(p.b,delta); - *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b); - } - row += bm->width * rset->rowstep; - iye += src->height - 1; + if (iy < (uint32_t)ctx->src->height) + { + if (!ctx->h_scaler((void*)rowtmp, ctx, false)) + return false; +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif + { + rowinc[x] += rowtmp[x]; + rowval[x] += rowinc[x] * iye; + rowinc[x] *= ctx->src->height - 1; + } + } + } else +#ifdef HAVE_LCD_COLOR + for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++) +#else + for (x = 0; x < (uint32_t)ctx->bm->width; x++) +#endif + rowval[x] += rowinc[x]; + ctx->output_row(oy, (void*)rowval, ctx); + iye += ctx->src->height - 1; } return true; } #endif /* HAVE_UPSCALER */ -#endif /* HAVE_LCD_COLOR */ -/* docs for this are still TODO, but it's Bresenham's again, used to skip or - repeat input pixels, and with the *ls values being used for "long steps" - that skip all the way, or nearly all the way, to the next transition of - the associated value. -*/ -#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8) -/* nearest-neighbor up/down/non-scaler */ -static inline bool scale_nearest(struct bitmap *bm, - struct dim *src, - struct rowset *rset, - bool remote, bool dither, - struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int), - void *args) +void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx) { + int col; + int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0); + uint8_t dy = DITHERY(row); +#ifdef HAVE_LCD_COLOR + struct uint32_rgb *qp = (struct uint32_rgb*)row_in; +#else + uint32_t *qp = (uint32_t*)row_in; +#endif + SDEBUGF("output_row: y: %d in: %p\n",row, row_in); +#if LCD_DEPTH == 2 +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + /* greyscale iPods */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; + int shift = 6; + int delta = 127; + unsigned bright; + unsigned data = 0; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + data |= (~bright & 3) << shift; + shift -= 2; + if (shift < 0) { + *dest++ = data; + data = 0; + shift = 6; + } + } + if (shift < 6) + *dest++ = data; +#elif LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * + (row >> 2); + int shift = 2 * (row & 3); + int delta = 127; + unsigned bright; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= (~bright & 3) << shift; + } +#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED + /* iAudio M3 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * + (row >> 3); + int shift = row & 7; + int delta = 127; + unsigned bright; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + bright = ((*qp++) + ctx->round) * + (uint64_t)ctx->divisor >> 32; + bright = (3 * bright + (bright >> 6) + delta) >> 8; + *dest++ |= vi_pattern[bright] << shift; + } +#endif /* LCD_PIXELFORMAT */ +#elif LCD_DEPTH == 16 + /* iriver h300, colour iPods, X5 */ + fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row; + int delta = 127; + unsigned r, g, b; + struct uint32_rgb q0; + + for (col = 0; col < ctx->bm->width; col++) { + if (ctx->dither) + delta = DITHERXDY(col,dy); + q0 = *qp++; + r = (q0.r + ctx->round) * (uint64_t)ctx->divisor >> 32; + g = (q0.g + ctx->round) * (uint64_t)ctx->divisor >> 32; + b = (q0.b + ctx->round) * (uint64_t)ctx->divisor >> 32; + r = (31 * r + (r >> 3) + delta) >> 8; + g = (63 * g + (g >> 2) + delta) >> 8; + b = (31 * b + (b >> 3) + delta) >> 8; + *dest++ = LCD_RGBPACK_LCD(r, g, b); + } +#endif /* LCD_DEPTH */ +} + +int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, + struct rowset *rset, unsigned char *buf, unsigned int len, + struct img_part* (*store_part)(void *args), + void *args) +{ + +#ifdef HAVE_UPSCALER const int sw = src->width; const int sh = src->height; const int dw = bm->width; const int dh = bm->height; - unsigned char *bitmap = bm->data; - const int rowstep = rset->rowstep; - const int rowstart = rset->rowstart; - const int rowstop = rset->rowstop; - const int fb_width = get_fb_width(bm, false); - long last_tick = current_tick; - /* yet/oyt will always be initialized before use, since they are set in the - inside loop, and not used elsewhere until the end of the outside loop. - */ - int ix, ox, lx, xe, iy, oy, ly, ye, yet = yet, oyt = oyt; - int xelim, ixls, xels, yelim, iyls, yels, p; - struct img_part *cur_part; -#ifndef HAVE_LCD_COLOR - fb_data *dest = dest, *dest_t; #endif -#ifdef HAVE_REMOTE_LCD - fb_remote_data *rdest = rdest, *rdest_t; -#endif - - SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw, - dh, remote); - ly = 0; - iy = 0; - ye = 0; - xelim = sw == dw - 1 ? dw : dw - 1; - ixls = xelim ? sw / xelim : 1; - xels = sw - ixls * (xelim ? xelim : 1); - yelim = sh == dh - 1 ? dh : dh - 1; - iyls = yelim ? sh / yelim : 1; - yels = iyls * (yelim ? yelim : 1); - int delta = 127; -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \ - (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING) - uint8_t buf[4]; - int data, oxt; -#endif -#if LCD_PIXELFORMAT == VERTICAL_PACKING || \ - LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \ - (defined(HAVE_REMOTE_LCD) && \ - (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \ - LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING)) - int bright, shift; -#endif - for (oy = rowstart; oy != rowstop;) { - SDEBUGF("oy=%d iy=%d\n", oy, iy); - if (last_tick != current_tick) - { - yield(); - last_tick = current_tick; - } - if (iy > ly && !skip_lines(args, iy - ly - 1)) - return false; - ly = iy; - - cur_part = store_part(args); - if (cur_part == NULL) - return false; - - lx = 0; - ix = 0; - xe = 0; -#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) - if(!remote) + int ret; +#ifdef HAVE_LCD_COLOR + unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width; #else - (void)remote; + unsigned int needed = sizeof(uint32_t) * 3 * bm->width; #endif -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - dest = (fb_data *)bitmap + fb_width * oy; -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - dest = (fb_data *)bitmap + fb_width * (oy >> 2); -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - dest = (fb_data *)bitmap + fb_width * (oy >> 3); +#if MAX_SC_STACK_ALLOC + uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? + 0 : needed]; #endif -#ifdef HAVE_REMOTE_LCD -#ifndef HAVE_LCD_COLOR - else -#endif - rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3); -#endif - for (ox = 0; ox < dw; ox++) { - while (cur_part->len <= ix - lx) - { - lx += cur_part->len; - cur_part = store_part(args); - if (cur_part == NULL) - return false; - } - cur_part->len -= ix - lx; - cur_part->buf += ix - lx; - lx = ix; -#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) - if(!remote) - { -#endif -#if LCD_PIXELFORMAT == HORIZONTAL_PACKING - /* greyscale iPods */ - buf[ox & 3] = brightness(*(cur_part->buf)); - if ((ox & 3) == 3 || ox == dw - 1) - { - dest_t = dest++; - oyt = oy; - yet = ye; - int xo = ox & ~3; - while(yet < dh) - { - data = 0; - for (oxt = 0; oxt < (ox & 3) + 1; oxt++) - { - if (dither) - delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf); - p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8; - data |= (~p & 3) << ((3 - oxt) << 1); - } - *dest_t = data; - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } - } -#elif LCD_PIXELFORMAT == VERTICAL_PACKING - /* iriver H1x0 */ - bright = brightness(*(cur_part->buf)); - dest_t = dest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = (oyt & 3) << 1; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *dest_t |= (~p & 3) << shift; - if ((rowstep > 0 && shift == 6) || shift == 0) - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED - bright = brightness(*(cur_part->buf)); - dest_t = dest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *dest_t |= vi_pat(p) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - dest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#endif /* LCD_PIXELFORMAT */ -#ifdef HAVE_REMOTE_LCD -#ifndef HAVE_LCD_COLOR - } else -#endif - { -#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED - bright = brightness(*(cur_part->buf)); - rdest_t = rdest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - - p = (3 * bright + (bright >> 6) + delta) >> 8; - *rdest_t |= vi_pat(p) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - rdest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#else - bright = brightness(*(cur_part->buf)); - rdest_t = rdest++; - oyt = oy; - yet = ye; - while(yet < dh) - { - shift = oyt & 7; - if (dither) - delta = dither_mat(oyt & 0xf, ox & 0xf); - p = (bright + delta) >> 8; - *rdest_t |= (~p & 1) << shift; - if ((rowstep > 0 && shift == 7) || shift == 0) - rdest_t += rowstep * fb_width; - yet += sh; - oyt += rowstep; - } -#endif - } -#endif - xe += xels; - ix += ixls; - while (xe > xelim) - { - xe -= xelim; - ix += 1; - } - } - oy = oyt; - ye = yet - yels; - iy += iyls; - while (ye > yelim) + len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, + sizeof(uint32_t)); + if (needed > len) + { +#if MAX_SC_STACK_ALLOC + if (needed > MAX_SC_STACK_ALLOC) { - ye -= yelim; - iy += 1; + DEBUGF("unable to allocate required buffer: %d needed, " + "%d available, %d permitted from stack\n", + needed, len, MAX_SC_STACK_ALLOC); + return 0; } + if (sizeof(sc_buf) < needed) + { + DEBUGF("failed to allocate large enough buffer on stack: " + "%d needed, only got %d", + needed, MAX_SC_STACK_ALLOC); + return 0; + } +#else + DEBUGF("unable to allocate required buffer: %d needed, " + "%d available\n", needed, len); + return 0; +#endif } - return true; -} -#endif -int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, - struct rowset *rset, bool remote, -#ifdef HAVE_LCD_COLOR - unsigned char *buf, unsigned int len, -#endif - struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int lines), - void *args) -{ - -#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD) - (void)skip_lines; -#endif -#ifdef HAVE_LCD_COLOR -#ifdef HAVE_REMOTE_LCD - if (!remote) -#endif - { -#ifdef HAVE_UPSCALER - const int sw = src->width; - const int sh = src->height; - const int dw = bm->width; - const int dh = bm->height; -#endif - int ret; - unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width; + struct scaler_context ctx; + cpu_boost(true); + ctx.store_part = store_part; + ctx.args = args; #if MAX_SC_STACK_ALLOC - uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? - 0 : needed]; - if (len && buf) -#endif - len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, - sizeof(uint32_t)); - if (needed > len) - { -#if MAX_SC_STACK_ALLOC - if (needed > MAX_SC_STACK_ALLOC) - { - DEBUGF("unable to allocate required buffer: %d needed, " - "%d available, %d permitted from stack\n", - needed, len, MAX_SC_STACK_ALLOC); - return 0; - } - if (sizeof(sc_buf) < needed) - { - DEBUGF("failed to allocate large enough buffer on stack: " - "%d needed, only got %d", - needed, MAX_SC_STACK_ALLOC); - return 0; - } + ctx.buf = needed > len ? sc_buf : buf; #else - DEBUGF("unable to allocate required buffer: %d needed, " - "%d available\n", needed, len); - return 0; + ctx.buf = buf; #endif - } - - bool (*h_scaler)(struct bitmap*, struct dim*, - struct uint32_rgb*, - struct scaler_context*, bool); - struct scaler_context ctx; - ctx.last_tick = current_tick; - cpu_boost(true); + ctx.len = len; + ctx.bm = bm; + ctx.src = src; + ctx.dither = dither; + ctx.output_row = output_row_native; #ifdef HAVE_UPSCALER - if (sw > dw) - { + if (sw > dw) + { #endif - h_scaler = scale_h_area; - scale_h_area_setup(bm, src, &ctx); + ctx.h_scaler = scale_h_area; + scale_h_area_setup(&ctx); #ifdef HAVE_UPSCALER - } else { - h_scaler = scale_h_linear; - scale_h_linear_setup(bm, src, &ctx); - } + } else { + ctx.h_scaler = scale_h_linear; + scale_h_linear_setup(&ctx); + } #endif - ctx.store_part = store_part; - ctx.args = args; -#if MAX_SC_STACK_ALLOC - ctx.buf = needed > len ? sc_buf : buf; -#else - ctx.buf = buf; -#endif - ctx.len = len; #ifdef HAVE_UPSCALER - if (sh > dh) + if (sh > dh) #endif - ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx); + ret = scale_v_area(rset, &ctx); #ifdef HAVE_UPSCALER - else - ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx); + else + ret = scale_v_linear(rset, &ctx); #endif - cpu_boost(false); - if (!ret) - return 0; - } -#ifdef HAVE_REMOTE_LCD - else -#endif -#endif /* HAVE_LCD_COLOR */ -#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD) - { - if (!scale_nearest(bm, src, rset, remote, dither, store_part, - skip_lines, args)) - return 0; - } -#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/ - return get_totalsize(bm, remote); + cpu_boost(false); + if (!ret) + return 0; + return BM_SIZE(bm->width,bm->height,bm->format,0); } diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h index 8a39db503a..451830742e 100644 --- a/apps/recorder/resize.h +++ b/apps/recorder/resize.h @@ -23,6 +23,7 @@ #include "config.h" #include "lcd.h" +#include "inttypes.h" /**************************************************************** * resize_on_load() @@ -45,16 +46,30 @@ struct img_part { int len; +#if !defined(HAVE_LCD_COLOR) && \ + (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) + uint8_t *buf; +#else struct uint8_rgb* buf; +#endif }; -int resize_on_load(struct bitmap *bm, bool dither, - struct dim *src, - struct rowset *tmp_row, bool remote, #ifdef HAVE_LCD_COLOR - unsigned char *buf, unsigned int len, +/* intermediate type used by the scaler for color output. greyscale version + uses uint32_t +*/ +struct uint32_rgb { + uint32_t r; + uint32_t g; + uint32_t b; +}; #endif + +int recalc_dimension(struct dim *dst, struct dim *src); + +int resize_on_load(struct bitmap *bm, bool dither, + struct dim *src, struct rowset *tmp_row, + unsigned char *buf, unsigned int len, struct img_part* (*store_part)(void *args), - bool (*skip_lines)(void *args, unsigned int lines), void *args); #endif /* _RESIZE_H_ */ diff --git a/firmware/export/lcd-remote.h b/firmware/export/lcd-remote.h index 3c013d657a..01df5a7eab 100644 --- a/firmware/export/lcd-remote.h +++ b/firmware/export/lcd-remote.h @@ -48,13 +48,17 @@ int remote_type(void); #if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \ || (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED) typedef unsigned short fb_remote_data; +#define FB_RDATA_SZ 2 #else typedef unsigned char fb_remote_data; +#define FB_RDATA_SZ 1 #endif #elif LCD_DEPTH <= 16 typedef unsigned short fb_remote_data; +#define FB_RDATA_SZ 2 #else typedef unsigned long fb_remote_data; +#define FB_RDATA_SZ 4 #endif /* common functions */ diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index ea5851e736..e435d174f2 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -75,13 +75,17 @@ struct viewport { #if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \ || (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED) typedef unsigned short fb_data; +#define FB_DATA_SZ 2 #else typedef unsigned char fb_data; +#define FB_DATA_SZ 1 #endif #elif LCD_DEPTH <= 16 typedef unsigned short fb_data; +#define FB_DATA_SZ 2 #else /* LCD_DEPTH > 16 */ typedef unsigned long fb_data; +#define FB_DATA_SZ 4 #endif /* LCD_DEPTH */ #else /* LCD_CHARCELLS */