Latest work on the bmp on-load scaler:

Macros for calculating size needed for bitmap load and scaling, so that
these can be compile-time constant when their inputs are.

Reduce size of bayer dither by chopping all but first row of dither
matrix, and replacing 2D lookup with 1D lookup and small calculation.

Move some functions not related to actual bmp file loading out of bmp.c.

A smaller brightness() for mono targets, and a higher-quality one for
greyscale targets, both replacing the division by 10 with a shift.

Port of the linear and area scalers to greyscale targets, this costs
some binsize but produces better output even when dithered to 2bpp.

Move duplicated row output code from inside vertical scalers to a
separate row output function.

Move some multiplies out of the line scaler, for a small speedup and
code size reduction, as well as a small improvement in accuracy for the
upscaling case.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19592 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Andrew Mahone 2008-12-26 07:03:22 +00:00
parent 7428c7cc5b
commit f7fa7e5ad5
8 changed files with 761 additions and 819 deletions

View file

@ -78,6 +78,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#include "playlist.h" #include "playlist.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
#include "scrollbar.h" #include "scrollbar.h"
#include "../recorder/bmp.h"
#endif #endif
#include "statusbar.h" #include "statusbar.h"
#include "menu.h" #include "menu.h"

View file

@ -19,7 +19,6 @@
* *
****************************************************************************/ ****************************************************************************/
#include "plugin.h" #include "plugin.h"
#include "lib/bmp.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
PLUGIN_HEADER PLUGIN_HEADER
@ -258,13 +257,9 @@ static int num_font = FONT_UI;
static int moves_font = FONT_UI; static int moves_font = FONT_UI;
static int moves_y = 0; static int moves_y = 0;
#ifdef HAVE_LCD_COLOR static unsigned char img_buf
static unsigned char *img_buf; [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)]
static size_t buf_len; __attribute__ ((aligned(16)));
#else
static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
__attribute__ ((aligned(16)));
#endif
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
static char albumart_path[MAX_PATH+1]; static char albumart_path[MAX_PATH+1];
#endif #endif
@ -343,13 +338,9 @@ static bool load_resize_bitmap(void)
main_bitmap.width = IMAGE_WIDTH; main_bitmap.width = IMAGE_WIDTH;
main_bitmap.height = IMAGE_HEIGHT; 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, rc = rb->read_bmp_file( filename, &main_bitmap,
buf_len, sizeof(img_buf),
FORMAT_NATIVE|FORMAT_RESIZE ); FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER);
if( rc > 0 ) if( rc > 0 )
{ {
puzzle_bmp_ptr = (const fb_data *)img_buf; puzzle_bmp_ptr = (const fb_data *)img_buf;
@ -574,7 +565,8 @@ static int puzzle_loop(void)
/* change picture */ /* change picture */
picmode = (picmode+1)%PICMODE_LAST_XXX; 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 do
{ {
load_success = load_resize_bitmap(); 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; 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; initial_bmp_path=(const char *)parameter;
picmode = PICMODE_INITIAL_PICTURE; picmode = PICMODE_INITIAL_PICTURE;
img_buf_path[0] = '\0'; 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 /* If launched as a viewer, just go straight to the game without
bothering with the splash or instructions page */ bothering with the splash or instructions page */

View file

@ -124,25 +124,10 @@ static const struct uint8_rgb bitfields[3][3] = {
}; };
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
/* canonical ordered dither matrix */ /* the full 16x16 Bayer dither matrix may be calculated quickly with this table
const unsigned char dither_matrix[16][16] = { */
{ 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, const unsigned char dither_table[16] =
{ 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 };
{ 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 }
};
#endif #endif
#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
@ -194,7 +179,7 @@ struct bmp_args {
short read_width; short read_width;
short width; short width;
short depth; short depth;
unsigned char buf[MAX_WIDTH * 4]; unsigned char buf[BM_MAX_WIDTH * 4];
struct uint8_rgb *palette; struct uint8_rgb *palette;
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
int cur_row; int cur_row;
@ -222,13 +207,14 @@ static unsigned int read_part_line(struct bmp_args *ba)
int i, cols, len; int i, cols, len;
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) #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; len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
#else #else
cols = width; cols = width;
len = read_width; len = read_width;
#endif #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); BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
ret = read(fd, ibuf, len); ret = read(fd, ibuf, len);
if (ret != len) if (ret != len)
@ -239,25 +225,25 @@ static unsigned int read_part_line(struct bmp_args *ba)
cols, len); cols, len);
return 0; return 0;
} }
for (i = 0; i < cols; i++) while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
{ {
switch (depth) switch (depth)
{ {
case 1: case 1:
if ((i & 7) == 0) data = *ibuf++;
data = *ibuf++; for (i = 0; i < 8; i++)
*buf = palette[(data >> 7) & 1]; {
data <<= 1; *buf++ = palette[data & 0x80 ? 1 : 0];
data <<= 1;
}
break; break;
case 4: case 4:
*buf = palette[*ibuf >> 4]; data = *ibuf++;
if (i & 1) *buf++ = palette[data >> 4];
ibuf++; *buf++ = palette[data & 0xf];
else
*ibuf <<= 4;
break; break;
case 8: case 8:
*buf = palette[*ibuf++]; *buf++ = palette[*ibuf++];
break; break;
case 15: case 15:
case 16: case 16:
@ -280,6 +266,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
component = data & 0xf8; component = data & 0xf8;
component |= component >> 5; component |= component >> 5;
buf->red = component; buf->red = component;
buf++;
ibuf += 2; ibuf += 2;
break; break;
case 32: case 32:
@ -289,11 +276,19 @@ static unsigned int read_part_line(struct bmp_args *ba)
buf->red = *ibuf++; buf->red = *ibuf++;
if (depth == 32) if (depth == 32)
ibuf++; ibuf++;
buf++;
break; 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) #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
cur_col += cols; cur_col += cols;
if (cur_col == width) 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; struct bmp_args *ba = (struct bmp_args *)args;
ba->part.len = read_part_line(ba); ba->part.len = read_part_line(ba);
#ifdef HAVE_LCD_COLOR
ba->part.buf = (struct uint8_rgb *)ba->buf; ba->part.buf = (struct uint8_rgb *)ba->buf;
#else
ba->part.buf = (uint8_t *)ba->buf;
#endif
if (ba->part.len) if (ba->part.len)
return &(ba->part); return &(ba->part);
else else
return NULL; 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 #endif
static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) 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; unsigned char *bitmap = bm->data;
struct uint8_rgb palette[256]; struct uint8_rgb palette[256];
bool remote = false;
struct rowset rset; struct rowset rset;
struct dim src_dim; struct dim src_dim;
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
bool remote = false;
unsigned int resize = IMG_NORESIZE; unsigned int resize = IMG_NORESIZE;
bool dither = false; bool dither = false;
bool transparent = false; bool transparent = false;
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
if (format & FORMAT_REMOTE) { if (format & FORMAT_REMOTE) {
remote = true; remote = true;
#if LCD_REMOTE_DEPTH == 1 #if LCD_REMOTE_DEPTH == 1
format = FORMAT_MONO; format = FORMAT_MONO;
#else
format &= ~FORMAT_REMOTE;
#endif #endif
} }
#endif /* HAVE_REMOTE_LCD */ #endif /* HAVE_REMOTE_LCD */
if (format & FORMAT_RESIZE) { if (format & FORMAT_RESIZE) {
resize = IMG_RESIZE; resize = IMG_RESIZE;
format &= ~FORMAT_RESIZE;
} }
if (format & FORMAT_TRANSPARENT) { if (format & FORMAT_TRANSPARENT) {
transparent = true; transparent = true;
format &= ~FORMAT_TRANSPARENT;
} }
if (format & FORMAT_DITHER) { if (format & FORMAT_DITHER) {
dither = true; dither = true;
format &= ~FORMAT_DITHER;
} }
#else #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, BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
src_dim.height, depth, padded_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 ((format & 3) == FORMAT_ANY) {
if (depth == 1) if (depth == 1)
format = (format & ~3); format = (format & ~3);
else else
format = (format & ~3) | FORMAT_NATIVE; format = (format & ~3) | FORMAT_NATIVE;
} }
bm->format = format & 3; bm->format = format & 1;
if ((format & 3) == FORMAT_MONO) if ((format & 1) == FORMAT_MONO)
{ {
resize &= ~IMG_RESIZE; resize &= ~IMG_RESIZE;
resize |= IMG_NORESIZE; resize |= IMG_NORESIZE;
remote = 0; remote = 0;
} }
#else #else
if (src_dim.width > MAX_WIDTH) if (src_dim.width > BM_MAX_WIDTH)
return -6; return -6;
#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ #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 (resize & IMG_RESIZE) {
if(format & FORMAT_KEEP_ASPECT) { if(format & FORMAT_KEEP_ASPECT) {
/* keep aspect ratio.. */ /* keep aspect ratio.. */
format &= ~FORMAT_KEEP_ASPECT;
struct dim resize_dim = { struct dim resize_dim = {
.width = bm->width, .width = bm->width,
.height = bm->height, .height = bm->height,
@ -506,6 +453,8 @@ int read_bmp_fd(int fd,
} }
} }
format &= 1;
if (!(resize & IMG_RESIZE)) { if (!(resize & IMG_RESIZE)) {
#endif #endif
/* returning image size */ /* returning image size */
@ -524,7 +473,7 @@ int read_bmp_fd(int fd,
rset.rowstop = -1; rset.rowstop = -1;
} }
totalsize = get_totalsize(bm, remote); totalsize = BM_SIZE(bm->width,bm->height,format,remote);
/* Check if this fits the buffer */ /* Check if this fits the buffer */
if (totalsize > maxsize) { 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 > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
#if LCD_DEPTH == 16 if (resize)
#ifdef HAVE_REMOTE_LCD return resize_on_load(bm, dither, &src_dim, &rset,
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
bitmap + totalsize, maxsize - totalsize, bitmap + totalsize, maxsize - totalsize,
#endif store_part_bmp, &ba);
store_part_bmp, skip_lines_bmp, &ba);
int fb_width = BM_WIDTH(bm->width,bm->format,remote);
#endif /* LCD_DEPTH */ #endif /* LCD_DEPTH */
int fb_width = get_fb_width(bm, remote);
int col, row; int col, row;
/* loop to read rows and put them to buffer */ /* loop to read rows and put them to buffer */
for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { 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 mask;
unsigned char *p; 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)) if (!read_part_line(&ba))
return -9; return -9;
#endif
/* Convert to destination format */ /* Convert to destination format */
qp = (struct uint8_rgb *) ba.buf; #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
#if LCD_DEPTH == 16 unsigned char dy = DITHERY(row);
if (format == FORMAT_NATIVE) if (format == FORMAT_NATIVE) {
{ #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
/* iriver h300, colour iPods, X5 */ if (remote) {
fb_data *dest = (fb_data *)bitmap + fb_width * row; #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
int delta = 127; /* iAudio X5/M5 remote */
unsigned r, g, b; fb_remote_data *dest = (fb_remote_data *)bitmap
struct uint8_rgb q0; + bm->width * (row >> 3);
int shift = row & 7;
int delta = 127;
unsigned bright;
for (col = 0; col < src_dim.width; col++) { for (col = 0; col < bm->width; col++) {
if (dither) if (dither)
delta = dither_mat(row & 0xf, col & 0xf); delta = DITHERXDY(col,dy);
if (!len) #if !defined(HAVE_LCD_COLOR) && \
{ (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
if(!(len = read_part_line(&ba))) bright = *qp++;
return -9; #else
else bright = brightness(*qp++);
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
#endif #endif
{ bright = (3 * bright + (bright >> 6) + delta) >> 8;
p = bitmap + fb_width * (row >> 3); *dest++ |= vi_pattern[bright] << shift;
mask = 1 << (row & 7); }
for (col = 0; col < src_dim.width; col++) #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 LCD_DEPTH == 2
if (!len) #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
{ /* greyscale iPods */
if(!(len = read_part_line(&ba))) fb_data *dest = (fb_data *)bitmap + fb_width * row;
return -9; int shift = 6;
else int delta = 127;
qp = (struct uint8_rgb *)ba.buf; 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--; if (shift < 6)
#endif *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) if (brightness(*qp++) < 128)
*p |= mask; *p |= mask;
p++; #endif
}
} }
} }
return totalsize; /* return the used buffer size. */ return totalsize; /* return the used buffer size. */

View file

@ -32,11 +32,7 @@
#define IMG_NORESIZE 0 #define IMG_NORESIZE 0
#define IMG_RESIZE 1 #define IMG_RESIZE 1
#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) #define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7)
#define MAX_WIDTH 8
#else
#define MAX_WIDTH LCD_WIDTH
#endif
struct uint8_rgb { struct uint8_rgb {
uint8_t blue; uint8_t blue;
@ -56,129 +52,144 @@ struct rowset {
}; };
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
extern const unsigned char dither_matrix[16][16]; extern const unsigned char dither_table[16];
static inline unsigned char dither_mat(unsigned int x, unsigned int y) #define DITHERY(y) (dither_table[(y) & 15] & 0xAA)
{ #define DITHERX(x) (dither_table[(x) & 15])
return dither_matrix[y][x]; #define DITHERXDY(x,dy) (DITHERX(x) ^ dy)
} #define DITHERDXY(dx,y) (dx ^ DITHERY(y))
#define DITHERXY(x,y) (DITHERX(x) ^ DITHERY(y))
#endif #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) static inline unsigned brightness(struct uint8_rgb color)
{ {
return (3 * (unsigned)color.red + 6 * (unsigned)color.green #if LCD_DEPTH > 1
+ (unsigned)color.blue) / 10; 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)) \ #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
|| (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
&& (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
extern const unsigned short vi_pattern[4]; extern const unsigned short vi_pattern[4];
static inline unsigned short vi_pat(unsigned int bright)
{
return vi_pattern[bright];
}
#endif #endif
static inline int get_fb_height(struct bitmap *bm, bool remote) /* Number of rows of data in a mono bitmap height pixels tall */
{ #define MONO_BM_HEIGHT(height) (((height) + 7) >> 3)
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;
#if !defined(HAVE_REMOTE_LCD) || \ /* Number of rows of datain a LCD native bitmap height pixels tall */
(defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
(void) remote; #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 #endif
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) /* Number of rows of data in a remote native bitmap height pixels tall. */
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;
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
if (remote && sizeof(fb_data) != sizeof(fb_remote_data)) #if LCD_REMOTE_DEPTH == 1 || \
sz = sizeof(fb_remote_data); (LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
else #define LCD_REMOTE_BM_HEIGHT(height) (((height) + 7) >> 3)
#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ #elif LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING
sz = sizeof(fb_data); #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() * read_bmp_file()

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
#include "config.h" #include "config.h"
#include "lcd.h" #include "lcd.h"
#include "inttypes.h"
/**************************************************************** /****************************************************************
* resize_on_load() * resize_on_load()
@ -45,16 +46,30 @@
struct img_part { struct img_part {
int len; 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; 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 #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 #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), struct img_part* (*store_part)(void *args),
bool (*skip_lines)(void *args, unsigned int lines),
void *args); void *args);
#endif /* _RESIZE_H_ */ #endif /* _RESIZE_H_ */

View file

@ -48,13 +48,17 @@ int remote_type(void);
#if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \ #if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \
|| (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED) || (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED)
typedef unsigned short fb_remote_data; typedef unsigned short fb_remote_data;
#define FB_RDATA_SZ 2
#else #else
typedef unsigned char fb_remote_data; typedef unsigned char fb_remote_data;
#define FB_RDATA_SZ 1
#endif #endif
#elif LCD_DEPTH <= 16 #elif LCD_DEPTH <= 16
typedef unsigned short fb_remote_data; typedef unsigned short fb_remote_data;
#define FB_RDATA_SZ 2
#else #else
typedef unsigned long fb_remote_data; typedef unsigned long fb_remote_data;
#define FB_RDATA_SZ 4
#endif #endif
/* common functions */ /* common functions */

View file

@ -75,13 +75,17 @@ struct viewport {
#if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \ #if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \
|| (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED) || (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED)
typedef unsigned short fb_data; typedef unsigned short fb_data;
#define FB_DATA_SZ 2
#else #else
typedef unsigned char fb_data; typedef unsigned char fb_data;
#define FB_DATA_SZ 1
#endif #endif
#elif LCD_DEPTH <= 16 #elif LCD_DEPTH <= 16
typedef unsigned short fb_data; typedef unsigned short fb_data;
#define FB_DATA_SZ 2
#else /* LCD_DEPTH > 16 */ #else /* LCD_DEPTH > 16 */
typedef unsigned long fb_data; typedef unsigned long fb_data;
#define FB_DATA_SZ 4
#endif /* LCD_DEPTH */ #endif /* LCD_DEPTH */
#else /* LCD_CHARCELLS */ #else /* LCD_CHARCELLS */