summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugin.h1
-rw-r--r--apps/plugins/sliding_puzzle.c32
-rw-r--r--apps/recorder/bmp.c323
-rw-r--r--apps/recorder/bmp.h221
-rw-r--r--apps/recorder/resize.c920
-rw-r--r--apps/recorder/resize.h25
-rw-r--r--firmware/export/lcd-remote.h4
-rw-r--r--firmware/export/lcd.h4
8 files changed, 736 insertions, 794 deletions
diff --git a/apps/plugin.h b/apps/plugin.h
index e16d9eb..20e3a71 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 85f4d32..fa9e093 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 cdff8cc..cc57464 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;
-
- 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;
+#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 < 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
+ bright = (3 * bright + (bright >> 6) + delta) >> 8;
+ *dest++ |= vi_pattern[bright] << shift;
}
- 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);
+#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
+ /* 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;
+ }
+ }
+ 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
+ } else
+#endif /* (LCD_DEPTH > 1) ||
+ defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
{
- p = bitmap + fb_width * (row >> 3);
+ p = bitmap + bm->width * (row >> 3);
mask = 1 << (row & 7);
- for (col = 0; col < src_dim.width; col++)
- {
-#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;
- }
- len--;
-#endif
+
+ 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 d1b1d7f..273e178 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;
+/* Number of rows of data in a mono bitmap height pixels tall */
+#define MONO_BM_HEIGHT(height) (((height) + 7) >> 3)
+
+/* 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
- int dst_height;
-#if !defined(HAVE_REMOTE_LCD) || \
- (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1))
- (void) remote;
+/* Number of rows of data in a remote native bitmap height pixels tall. */
+#ifdef HAVE_REMOTE_LCD
+#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
-#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;
-}
+/* 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
-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;
+/* 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
- int dst_width;
-#if !defined(HAVE_REMOTE_LCD) || \
- (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1))
- (void) remote;
+/* 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
-#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;
-}
+/* 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
-static inline int get_totalsize(struct bitmap *bm, bool remote)
-{
- int sz;
-#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);
+/* 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)
- return get_fb_width(bm, remote) * get_fb_height(bm, remote) * 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 e415010..3c1d34f 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))
+ rowinc[x] = -rowtmp[x];
+ rowval[x] = rowtmp[x] * (ctx->bm->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;
+ }
}
- }
- 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;
+ } 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)
{
- 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 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
- (void)remote;
-#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);
-#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)
- {
+ 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 */
- 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)
- {
+ 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;
- 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;
+ shift = 6;
}
}
+ if (shift < 6)
+ *dest++ = data;
#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);
+ fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
+ (row >> 2);
+ int shift = 2 * (row & 3);
+ int delta = 127;
+ unsigned bright;
- 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;
+ 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
- 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);
+ /* iAudio M3 */
+ fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
+ (row >> 3);
+ int shift = row & 7;
+ int delta = 127;
+ unsigned bright;
- 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;
+ 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 */
-#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);
+#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;
- 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;
+ 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
- }
-#endif
- xe += xels;
- ix += ixls;
- while (xe > xelim)
- {
- xe -= xelim;
- ix += 1;
- }
- }
- oy = oyt;
- ye = yet - yels;
- iy += iyls;
- while (ye > yelim)
- {
- ye -= yelim;
- iy += 1;
- }
- }
- return true;
+#endif /* LCD_DEPTH */
}
-#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 rowset *rset, unsigned char *buf, unsigned int len,
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;
+#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;
#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;
+ unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
+#else
+ unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
#endif
- int ret;
- unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width;
#if MAX_SC_STACK_ALLOC
- uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
- 0 : needed];
- if (len && buf)
+ uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
+ 0 : needed];
#endif
- len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len,
- sizeof(uint32_t));
- if (needed > len)
- {
+ 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;
- }
+ 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;
+ }
#else
- DEBUGF("unable to allocate required buffer: %d needed, "
- "%d available\n", needed, len);
- return 0;
+ DEBUGF("unable to allocate required buffer: %d needed, "
+ "%d available\n", needed, len);
+ return 0;
#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);
-#ifdef HAVE_UPSCALER
- if (sw > dw)
- {
-#endif
- h_scaler = scale_h_area;
- scale_h_area_setup(bm, src, &ctx);
-#ifdef HAVE_UPSCALER
- } else {
- h_scaler = scale_h_linear;
- scale_h_linear_setup(bm, src, &ctx);
- }
-#endif
- ctx.store_part = store_part;
- ctx.args = args;
+ struct scaler_context ctx;
+ cpu_boost(true);
+ ctx.store_part = store_part;
+ ctx.args = args;
#if MAX_SC_STACK_ALLOC
- ctx.buf = needed > len ? sc_buf : buf;
+ ctx.buf = needed > len ? sc_buf : buf;
#else
- ctx.buf = buf;
+ ctx.buf = buf;
#endif
- ctx.len = len;
+ ctx.len = len;
+ ctx.bm = bm;
+ ctx.src = src;
+ ctx.dither = dither;
+ ctx.output_row = output_row_native;
#ifdef HAVE_UPSCALER
- if (sh > dh)
+ if (sw > dw)
+ {
#endif
- ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx);
+ ctx.h_scaler = scale_h_area;
+ scale_h_area_setup(&ctx);
#ifdef HAVE_UPSCALER
- else
- ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx);
+ } else {
+ ctx.h_scaler = scale_h_linear;
+ scale_h_linear_setup(&ctx);
+ }
#endif
- cpu_boost(false);
- if (!ret)
- return 0;
- }
-#ifdef HAVE_REMOTE_LCD
- else
+#ifdef HAVE_UPSCALER
+ if (sh > dh)
#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);
+ ret = scale_v_area(rset, &ctx);
+#ifdef HAVE_UPSCALER
+ else
+ ret = scale_v_linear(rset, &ctx);
+#endif
+ 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 8a39db5..4518307 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 3c013d6..01df5a7 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 ea5851e..e435d17 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 */