Index: apps/recorder/albumart.c =================================================================== --- apps/recorder/albumart.c (revision 15825) +++ apps/recorder/albumart.c (working copy) @@ -125,7 +125,7 @@ * If a matching bitmap is found, its filename is stored in buf. * Return value is true if a bitmap was found, false otherwise. */ -static bool search_files(const struct mp3entry *id3, const char *size_string, +bool albumart_search_files(const struct mp3entry *id3, const char *size_string, char *buf, int buflen) { char path[MAX_PATH + 1]; @@ -228,12 +228,12 @@ data->albumart_max_width, data->albumart_max_height); /* First we look for a bitmap of the right size */ - if (search_files(id3, size_string, buf, buflen)) + if (albumart_search_files(id3, size_string, buf, buflen)) return true; /* Then we look for generic bitmaps */ *size_string = 0; - return search_files(id3, size_string, buf, buflen); + return albumart_search_files(id3, size_string, buf, buflen); } /* Draw the album art bitmap from the given handle ID onto the given WPS. Index: apps/recorder/albumart.h =================================================================== --- apps/recorder/albumart.h (revision 15825) +++ apps/recorder/albumart.h (working copy) @@ -31,6 +31,12 @@ * Returns true if a bitmap was found, false otherwise */ bool find_albumart(const struct mp3entry *id3, char *buf, int buflen); +/* Same as above but you may specify a size string (e.g. "100x100") + * to load specifically this bitmap. Returns false if no file found, + * else fills in the filename into buf and returns true */ +bool albumart_search_files(const struct mp3entry *id3, const char *size_string, + char *buf, int buflen); + /* Draw the album art bitmap from the given handle ID onto the given WPS. Call with clear = true to clear the bitmap instead of drawing it. */ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); Index: apps/plugins/sliding_puzzle.c =================================================================== --- apps/plugins/sliding_puzzle.c (revision 15825) +++ apps/plugins/sliding_puzzle.c (working copy) @@ -17,6 +17,7 @@ * ****************************************************************************/ #include "plugin.h" +#include "bmp.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER @@ -95,10 +96,57 @@ #endif static struct plugin_api* rb; -static int spots[20]; -static int hole = 19, moves; +#define SPOTS_X 5 +#define SPOTS_Y 4 +#define NUM_SPOTS (SPOTS_X*SPOTS_Y) +#define HOLE_ID (NUM_SPOTS) +#define INITIAL_HOLE (HOLE_ID-1) +#if LCD_DEPTH>1 +#define IMAGE_SIZE ( (LCD_WIDTH1 +static int img_buf_free; +static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*2]; +static unsigned char *img_buf_ptr = img_buf; +static const char *const default_bmp_path="/.rockbox/rocks/games/sliding_puzzle.bmp"; +#ifdef HAVE_ALBUMART +static char albumart_path[MAX_PATH+1]; +#endif +/* default_bmp_path points to either DEFAULT_BMP_PATH or selected + bitmap if this game is launched as a viewer for a .bmp file */ +static const char * initial_bmp_path=NULL; +#if LCD_DEPTH==16 +#define DEPTH_BYTES 2 +#endif + +#else static unsigned char picture[20][32] = { { 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0xf8, 0xd9, 0x10, 0xb0, 0x60, 0xc0, 0x80, 0x00, 0x30, 0x78, @@ -200,16 +248,124 @@ 0x55, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xaa } }; +#endif +#if LCD_DEPTH>1 +#ifdef HAVE_ALBUMART +const char * get_albumart_bmp_path(void) +{ + struct mp3entry* track = rb->audio_current_track(); + + if (!track || !track->path || track->path[0] == '\0') + return NULL; + + if (!rb->plugin_albumart_search_files(track, "", albumart_path, MAX_PATH ) ) + return NULL; + + albumart_path[ MAX_PATH ] = '\0'; + return albumart_path; +} +#endif + +const char * get_random_bmp_path(void) +{ + return(initial_bmp_path); +} + +static bool load_resize_bitmap(void) +{ + struct bitmap temp_bitmap; + int rc; + img_buf_ptr = img_buf; + temp_bitmap.data = img_buf_ptr; + img_buf_free = sizeof(img_buf); + + const char * filename = NULL; + + switch( pic ){ + case PICMODE_NUMERALS: + default: + return(true); +#ifdef HAVE_ALBUMART + case PICMODE_ALBUM_ART: + if(NULL == (filename=get_albumart_bmp_path()) ) + filename = default_bmp_path; + break; +#endif +/* + case PICMODE_RANDOM: + if(NULL == (filename=get_random_bmp_path()) ) + filename = initial_bmp_path; + break; +*/ + case PICMODE_DEFAULT_PICTURE: + filename = initial_bmp_path; + break; + }; + + rc = read_resize_bmp_file( filename, &temp_bitmap, img_buf_free, + FORMAT_ANY|FORMAT_TRANSPARENT, + IMAGE_WIDTH, IMAGE_HEIGHT, + RESIZE_BMP_INCREASE|RESIZE_BMP_DECREASE|RESIZE_BMP_IGNORE_ASPECT, + rb ); + if(rc <= 0) + { + /* last try, go for default bmp */ + rc = read_resize_bmp_file( default_bmp_path, &temp_bitmap, img_buf_free, + FORMAT_ANY|FORMAT_TRANSPARENT, + IMAGE_WIDTH, IMAGE_HEIGHT, + RESIZE_BMP_INCREASE|RESIZE_BMP_DECREASE|RESIZE_BMP_IGNORE_ASPECT, + rb ); + if(rc <= 0 ) + return(false); + } + + /* set up the empty square */ +#if LCD_DEPTH==16 + int i; + for(i=0;imemset(img_buf+DEPTH_BYTES*( + (INITIAL_HOLE%SPOTS_X)*SPOTS_WIDTH+ + ((INITIAL_HOLE/SPOTS_X)*SPOTS_HEIGHT+i)*IMAGE_WIDTH), + 0,DEPTH_BYTES*SPOTS_WIDTH); +#endif + + return(true); +}; +#endif + /* draws a spot at the coordinates (x,y), range of p is 1-20 */ static void draw_spot(int p, int x, int y) { - if (pic || p==20) { - rb->lcd_mono_bitmap (picture[p-1], x, y, 16, 16); + if (p == HOLE_ID) + { +#if LCD_DEPTH==1 + rb->lcd_mono_bitmap(picture[p-1], x, y, SPOTS_WIDTH, SPOTS_HEIGHT); +#elif LCD_DEPTH==2 + /* we just use a black square */ + rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); + rb->lcd_set_background(LCD_BLACK); + rb->lcd_fillrect(x,y,SPOTS_WIDTH,SPOTS_HEIGHT); +#else + /* in theory this could be any special bitmap to represent the hole */ + rb->lcd_bitmap_part( (fb_data *)img_buf, ((p-1)%SPOTS_X)*SPOTS_WIDTH, + ((p-1)/SPOTS_X)*SPOTS_HEIGHT, + IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT); +#endif + } + else if (pic != PICMODE_NUMERALS) + { +#if LCD_DEPTH==1 + rb->lcd_mono_bitmap(picture[p-1], x, y, SPOTS_WIDTH, SPOTS_HEIGHT); +#else + rb->lcd_bitmap_part( (fb_data *)img_buf, ((p-1)%SPOTS_X)*SPOTS_WIDTH, + ((p-1)/SPOTS_X)*SPOTS_HEIGHT, + IMAGE_WIDTH, x, y, SPOTS_WIDTH, SPOTS_HEIGHT); +#endif } else { - rb->lcd_drawrect(x, y, 16, 16); + rb->lcd_drawrect(x, y, SPOTS_WIDTH, SPOTS_HEIGHT); rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - rb->lcd_fillrect(x+1, y+1, 14, 14); + rb->lcd_fillrect(x+1, y+1, SPOTS_WIDTH-2, SPOTS_HEIGHT-2); rb->lcd_set_drawmode(DRMODE_SOLID); rb->snprintf(s, sizeof(s), "%d", p); rb->lcd_putsxy(x+2, y+4, (unsigned char *)s); @@ -220,7 +376,7 @@ static bool puzzle_finished(void) { int i; - for (i=0; i<20; i++) + for (i=0; isnprintf(s, sizeof(s), "%d", moves); - rb->lcd_putsxy(85, 20, (unsigned char *)s); +#if (LCD_WIDTH>IMAGE_SIZE) + rb->lcd_putsxy(IMAGE_WIDTH+5, 20, (unsigned char *)s); +#else + rb->lcd_putsxy(5, IMAGE_HEIGHT+20, (unsigned char *)s); +#endif - for (i=4; i<=16; i+=4) { - draw_spot(20, (hole%5)*16, (hole/5)*16); - draw_spot(spots[hole], (hole%5)*16 + x*i, (hole/5)*16 + y*i); - rb->lcd_update(); + for(i=1;i<=4;i++) + { + draw_spot(HOLE_ID, + (hole%SPOTS_X)*SPOTS_WIDTH, + (hole/SPOTS_X)*SPOTS_HEIGHT); + draw_spot(spots[hole], + (hole%SPOTS_X)*SPOTS_WIDTH + (i*x*SPOTS_WIDTH)/5, + (hole/SPOTS_X)*SPOTS_HEIGHT + (i*y*SPOTS_HEIGHT)/5); + rb->lcd_update(); + rb->sleep(HZ/50); } - spots[hole] = 20; + draw_spot(HOLE_ID, + (hole%SPOTS_X)*SPOTS_WIDTH, + (hole/SPOTS_X)*SPOTS_HEIGHT); + draw_spot(spots[hole], + ((hole%SPOTS_X)+x)*SPOTS_WIDTH, + ((hole/SPOTS_X)+y)*SPOTS_HEIGHT); + rb->lcd_update(); + + spots[hole] = HOLE_ID; } /* initializes the puzzle */ static void puzzle_init(void) { - int i, r, temp, tsp[20]; + int i, r, temp, tsp[NUM_SPOTS]; + moves = 0; rb->lcd_clear_display(); - rb->lcd_drawrect(80, 0, 32, 64); - rb->lcd_putsxy(81, 10, (unsigned char *)"Moves"); rb->snprintf(s, sizeof(s), "%d", moves); - rb->lcd_putsxy(85, 20, (unsigned char *)s); + +#if (LCD_WIDTH>IMAGE_SIZE) + rb->lcd_drawrect(IMAGE_WIDTH, 0, 32, 64); + rb->lcd_putsxy(IMAGE_WIDTH+1, 10, (unsigned char *)"Moves"); + rb->lcd_putsxy(IMAGE_WIDTH+5, 20, (unsigned char *)s); +#else + rb->lcd_drawrect(0, IMAGE_HEIGHT, 32, 64); + rb->lcd_putsxy(1, IMAGE_HEIGHT+10, (unsigned char *)"Moves"); + rb->lcd_putsxy(5, IMAGE_HEIGHT+20, (unsigned char *)s); +#endif /* shuffle spots */ - for (i=19; i>=0; i--) { + for (i=NUM_SPOTS-1; i>=0; i--) { r = (rb->rand() % (i+1)); temp = spots[r]; spots[r] = spots[i]; spots[i] = temp; - if (spots[i]==20) + if (spots[i]==HOLE_ID) hole = i; } /* test if the puzzle is solvable */ - for (i=0; i<20; i++) + for (i=0; ilcd_update(); } @@ -338,29 +521,36 @@ break; #endif /* change picture */ - pic = (pic==true?false:true); - for (i=0; i<20; i++) - draw_spot(spots[i], (i%5)*16, (i/5)*16); + pic = (pic+1)%PICMODE_LAST_XXX; +#if LCD_DEPTH>1 + if(pic != PICMODE_NUMERALS ) + if(!load_resize_bitmap()) + return PLUGIN_OK; +#endif + for (i=0; ilcd_update(); break; case BUTTON_LEFT: - if ((hole%5)<4 && !puzzle_finished()) + if ((hole%SPOTS_X)<(SPOTS_X-1) && !puzzle_finished()) move_spot(-1, 0); break; case BUTTON_RIGHT: - if ((hole%5)>0 && !puzzle_finished()) + if ((hole%SPOTS_X)>0 && !puzzle_finished()) move_spot(1, 0); break; case PUZZLE_UP: - if ((hole/5)<3 && !puzzle_finished()) + if ((hole/SPOTS_X)<(SPOTS_Y-1) && !puzzle_finished()) move_spot(0, -1); break; case PUZZLE_DOWN: - if ((hole/5)>0 && !puzzle_finished()) + if ((hole/SPOTS_X)>0 && !puzzle_finished()) move_spot(0, 1); break; @@ -378,47 +568,114 @@ { int i, w, h; - (void)parameter; rb = api; + +#if LCD_DEPTH>1 + if(parameter==NULL) + initial_bmp_path=default_bmp_path; + else + initial_bmp_path=(const char *)parameter; +#else + if(parameter!=NULL) + { + rb->splash( HZ*2, "Cannot be launched as a viewer"); + return PLUGIN_OK; + } +#endif + + /* If launched as a viewer, just go straight to the game without + bothering with the spash or instructions page */ + if(parameter==NULL) + { + /* print title */ + rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h); + w = (w+1)/2; + h = (h+1)/2; + rb->lcd_clear_display(); + rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h, + (unsigned char *)"Sliding Puzzle"); + rb->lcd_update(); + rb->sleep(HZ); - /* print title */ - rb->lcd_getstringsize((unsigned char *)"Sliding Puzzle", &w, &h); - w = (w+1)/2; - h = (h+1)/2; - rb->lcd_clear_display(); - rb->lcd_putsxy(LCD_WIDTH/2-w, (LCD_HEIGHT/2)-h, (unsigned char *)"Sliding Puzzle"); - rb->lcd_update(); - rb->sleep(HZ); - - /* print instructions */ - rb->lcd_clear_display(); - rb->lcd_setfont(FONT_SYSFIXED); -#if CONFIG_KEYPAD == RECORDER_PAD - rb->lcd_putsxy(3, 18, "[OFF] to stop"); - rb->lcd_putsxy(3, 28, "[F1] shuffle"); - rb->lcd_putsxy(3, 38, "[F2] change pic"); + /* print instructions */ + rb->lcd_clear_display(); + rb->lcd_setfont(FONT_SYSFIXED); +#if CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ARCHOS_AV300_PAD + rb->lcd_putsxy(3, 18, "[OFF] to stop"); + rb->lcd_putsxy(3, 28, "[F1] shuffle"); + rb->lcd_putsxy(3, 38, "[F2] change pic"); #elif CONFIG_KEYPAD == ONDIO_PAD - rb->lcd_putsxy(0, 18, "[OFF] to stop"); - rb->lcd_putsxy(0, 28, "[MODE..] shuffle"); - rb->lcd_putsxy(0, 38, "[MODE] change pic"); + rb->lcd_putsxy(0, 18, "[OFF] to stop"); + rb->lcd_putsxy(0, 28, "[MODE..] shuffle"); + rb->lcd_putsxy(0, 38, "[MODE] change pic"); #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) - rb->lcd_putsxy(0, 18, "[S-MENU] to stop"); - rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle"); - rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic"); + rb->lcd_putsxy(0, 18, "[S-MENU] to stop"); + rb->lcd_putsxy(0, 28, "[S-LEFT] shuffle"); + rb->lcd_putsxy(0, 38, "[S-RIGHT] change pic"); +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ + (CONFIG_KEYPAD == IRIVER_H300_PAD) + rb->lcd_putsxy(0, 18, "[STOP] to stop"); + rb->lcd_putsxy(0, 28, "[SELECT] shuffle"); + rb->lcd_putsxy(0, 38, "[PLAY] change pic"); +#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD + rb->lcd_putsxy(0, 18, "[OFF] to stop"); + rb->lcd_putsxy(0, 28, "[REC] shuffle"); + rb->lcd_putsxy(0, 38, "[PLAY] change pic"); +#elif CONFIG_KEYPAD == GIGABEAT_PAD + rb->lcd_putsxy(0, 18, "[OFF] to stop"); + rb->lcd_putsxy(0, 28, "[SELECT] shuffle"); + rb->lcd_putsxy(0, 38, "[A] change pic"); +#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \ + (CONFIG_KEYPAD == SANSE_C200_PAD) + rb->lcd_putsxy(0, 18, "[OFF] to stop"); + rb->lcd_putsxy(0, 28, "[REC] shuffle"); + rb->lcd_putsxy(0, 38, "[SELECT] change pic"); +#elif CONFIG_KEYPAD == IRIVER_H10_PAD + rb->lcd_putsxy(0, 18, "[OFF] to stop"); + rb->lcd_putsxy(0, 28, "[REW] shuffle"); + rb->lcd_putsxy(0, 38, "[PLAY] change pic"); #endif - rb->lcd_update(); - rb->button_get_w_tmo(HZ*2); +#ifdef HAVE_ALBUMART + rb->lcd_putsxy(0,48," pic->albumart->num"); +#else + rb->lcd_putsxy(0,48," pic<->num"); +#endif + rb->lcd_update(); + rb->button_get_w_tmo(HZ*2); + } + hole = INITIAL_HOLE; + +#if LCD_DEPTH>1 + if( !load_resize_bitmap() ) + { + rb->lcd_clear_display(); + rb->lcd_putsxy(20,20,"Failed to load bitmap!"); + rb->lcd_update(); + rb->sleep(HZ*2); + return PLUGIN_OK; + } + + rb->lcd_set_background(LCD_BLACK); + rb->lcd_set_foreground(LCD_WHITE); + rb->lcd_set_backdrop(NULL); +#endif rb->lcd_clear_display(); - rb->lcd_drawrect(80, 0, 32, 64); - rb->lcd_putsxy(81, 10, (unsigned char *)"Moves"); - for (i=0; i<20; i++) { +#if (LCD_WIDTH>IMAGE_SIZE) + rb->lcd_drawrect(IMAGE_WIDTH, 0, 32, 64); + rb->lcd_putsxy(IMAGE_WIDTH+1, 10, (unsigned char *)"Moves"); +#else + rb->lcd_drawrect(0,IMAGE_HEIGHT,32,64); + rb->lcd_putsxy(1,IMAGE_HEIGHT+10, (unsigned char *)"Moves"); +#endif + + for (i=0; ilcd_update(); rb->sleep(HZ*2); Index: apps/plugins/viewers.config =================================================================== --- apps/plugins/viewers.config (revision 15825) +++ apps/plugins/viewers.config (working copy) @@ -26,6 +26,7 @@ wav,viewers/wavview,10 wav,viewers/test_codec,- bmp,apps/rockpaint,11 +bmp,games/sliding_puzzle,11 mpg,viewers/mpegplayer,4 mpeg,viewers/mpegplayer,4 iriver,viewers/iriver_flash,3 Index: apps/plugins/lib/SOURCES =================================================================== --- apps/plugins/lib/SOURCES (revision 15825) +++ apps/plugins/lib/SOURCES (working copy) @@ -25,7 +25,7 @@ xlcd_core.c xlcd_draw.c xlcd_scroll.c -#ifdef HAVE_LCD_COLOR +#if LCD_DEPTH>1 bmp.c #endif #endif Index: apps/plugins/lib/bmp.c =================================================================== --- apps/plugins/lib/bmp.c (revision 15825) +++ apps/plugins/lib/bmp.c (working copy) @@ -17,18 +17,107 @@ * ****************************************************************************/ +#include +#include +#include #include "bmp.h" #include "lcd.h" #include "file.h" -#include "lcd.h" #include "system.h" #define LE16(x) (htole16(x))&0xff, ((htole16(x))>>8)&0xff #define LE32(x) (htole32(x))&0xff, ((htole32(x))>>8)&0xff, ((htole32(x))>>16)&0xff, ((htole32(x))>>24)&0xff +#include "inttypes.h" +#ifdef HAVE_REMOTE_LCD +#include "lcd-remote.h" +#endif +#include "config.h" + +#ifdef __GNUC__ +#define STRUCT_PACKED __attribute__((packed)) +#else +#define STRUCT_PACKED +#pragma pack (push, 2) +#endif + +#define FACT_SCALE 1000 +/* BMP header structure */ +struct bmp_header { + uint16_t type; /* signature - 'BM' */ + uint32_t size; /* file size in bytes */ + uint16_t reserved1; /* 0 */ + uint16_t reserved2; /* 0 */ + uint32_t off_bits; /* offset to bitmap */ + uint32_t struct_size; /* size of this struct (40) */ + uint32_t width; /* bmap width in pixels */ + uint32_t height; /* bmap height in pixels */ + uint16_t planes; /* num planes - always 1 */ + uint16_t bit_count; /* bits per pixel */ + uint32_t compression; /* compression flag */ + uint32_t size_image; /* image size in bytes */ + int32_t x_pels_per_meter; /* horz resolution */ + int32_t y_pels_per_meter; /* vert resolution */ + uint32_t clr_used; /* 0 -> color table size */ + uint32_t clr_important; /* important color count */ +} STRUCT_PACKED; + +union rgb_union { + struct { /* Little endian */ + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char reserved; + }; + uint32_t raw; +}; + +/* maximum bitmap width which can be read: */ +#define MAX_WIDTH 1280 +/* Buffer for one line */ +//static uint32_t bmpbuf[MAX_WIDTH]; +static union rgb_union bmpbuf[MAX_WIDTH]; + +/* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */ +static const unsigned char bitfields[3][12] = { + { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */ + { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */ + { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */ +}; + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) +/* canonical ordered dither matrix */ +static 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 } +}; +#endif + +#if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ + && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) +static const fb_remote_data remote_pattern[4] = { + 0x0101, 0x0100, 0x0001, 0x0000 +}; +#endif + /** * Save to 24 bit bitmap. */ +#ifdef HAVE_LCD_COLOR int save_bmp_file( char* filename, struct bitmap *bm, struct plugin_api* rb ) { /* I'm not really sure about this one :) */ @@ -82,3 +171,564 @@ rb->close( fh ); return 1; } +#endif + +/* little endian functions */ +static inline unsigned readshort(uint16_t *value) +{ + unsigned char* bytes = (unsigned char*) value; + return (unsigned)bytes[0] | ((unsigned)bytes[1] << 8); +} + +static inline uint32_t readlong(uint32_t *value) +{ + unsigned char* bytes = (unsigned char*) value; + return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24); +} + +static inline unsigned brightness(union rgb_union color) +{ + return (3 * (unsigned)color.red + 6 * (unsigned)color.green + + (unsigned)color.blue) / 10; +} + + +static void set_pixel(int format, + unsigned char *bitmap, + bool dither, + union rgb_union color, + int dst_padded_width, + int dst_x, + int dst_y) +{ +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + bool remote = format & FORMAT_REMOTE; + format &= ~FORMAT_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) + int delta = (dither)?dither_matrix[dst_y & 0xf][dst_x & 0xf]:127; + unsigned bright = brightness(color); + bright = (3 * bright + (bright >> 6) + delta) >> 8; + ((fb_remote_data *)bitmap)[dst_padded_width * (dst_y >> 3)+dst_x] |= + remote_pattern[bright] << (dst_y & 7); +# endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + } else +# endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { + int delta = (dither)?dither_matrix[dst_y & 0xf][dst_x & 0xf]:127; +# if LCD_DEPTH == 2 + unsigned bright = brightness(color); + bright = (3 * bright + (bright >> 6) + delta) >> 8; +# if LCD_PIXELFORMAT == VERTICAL_PACKING + /* iriver H1x0 */ + ((fb_data *)bitmap)[dst_padded_width * (dst_y >> 2)+dst_x] |= (~bright & 3) << (2 * (dst_y & 3)); +# else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */ + /* greyscale iPods */ + ((fb_data *)bitmap)[dst_padded_width * dst_y + (dst_x >> 2)] |= (~bright & 3) << (6 - 2 * (dst_x & 3)); +# endif /* LCD_PIXELFORMAT */ +# elif LCD_DEPTH == 16 + /* iriver h300, colour iPods, X5 */ + unsigned r = (31 * color.red + (color.red >> 3) + delta) >> 8; + unsigned g = (63 * color.green + (color.green >> 2) + delta) >> 8; + unsigned b = (31 * color.blue + (color.blue >> 3) + delta) >> 8; + ((fb_data *)bitmap)[dst_padded_width * dst_y + dst_x] = LCD_RGBPACK_LCD(r, g, b); +# endif /* LCD_DEPTH */ + } + } else +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + if (brightness(color) < 128) + bitmap[dst_padded_width * (dst_y >> 3)+dst_x] |= 1 << (dst_y & 7); + } +} + + + +/****************************************************************************** + * read_resize_bmp_fd() + * + * Reads a BMP from a file descriptor and puts the data in rockbox format in *bitmap. + * + *****************************************************************************/ +int read_resize_bmp_fd( int fd, + struct bitmap *bm, + int maxsize, + int format, + int dst_maxwidth, + int dst_maxheight, + int flags, + struct plugin_api* rb) +{ + struct bmp_header bmph; + int src_w, src_h, src_padded_width; + int dst_w, dst_h, dst_padded_width, dst_padded_height; + int row, ret; + int fact_w = FACT_SCALE; + int fact_h = FACT_SCALE; + int top = 0,decrement_y = 0; + int left = 0,decrement_x = 0; + int depth, numcolors, compression, totalsize; + + unsigned char *bitmap = bm->data; + union rgb_union palette[256]; + bool dither = false; +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + bool transparent = false; +#ifdef HAVE_REMOTE_LCD + bool remote = false; + + 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_TRANSPARENT) { + transparent = true; + format &= ~FORMAT_TRANSPARENT; + } + if (format & FORMAT_DITHER) { + dither = true; + format &= ~FORMAT_DITHER; + } +#else + + format = FORMAT_MONO; +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + + /* read fileheader */ + ret = rb->read(fd, &bmph, sizeof(struct bmp_header)); + if (ret < 0) { + return ret * 10 - 2; + } + + if (ret != sizeof(struct bmp_header)) { + DEBUGF("read_bmp_file: can't read BMP header."); + return -3; + } + + /* check bitmap file signature */ + if (readshort(&bmph.type)!=0x4d42) { + DEBUGF("read_bmp_file: wring signature."); + return -3; + } + /* read the source dimensions */ + src_w = readlong(&bmph.width); + src_h = readlong(&bmph.height); + + /* Exit if too wide */ + if (((flags & RESIZE_BMP_NONE)==0 && (src_w > MAX_WIDTH)) || + ((flags & RESIZE_BMP_NONE) && (src_w > LCD_WIDTH))) { + DEBUGF("read_bmp_file: Bitmap is too wide (%d pixels, max is %d)\n", + src_w, MAX_WIDTH); + return -4; + } + + /* Calculate resize factors and image size */ + if (dst_maxwidth<=0 || dst_maxheight<=0) + { + dst_w = src_w; + dst_h = src_h; + } + else + { + dst_w = dst_maxwidth; + dst_h = dst_maxheight; + if (flags & RESIZE_BMP_FILL) + { + int aspect_src = src_w*FACT_SCALE/src_h; + int aspect_dst = dst_maxwidth*FACT_SCALE/dst_maxheight; + if (aspect_dst >= aspect_src) + { /* adjust height */ + decrement_y = (dst_maxheight * aspect_dst / aspect_src) - dst_maxheight; + } + else + { /* adjust width */ + decrement_x = (dst_maxwidth * aspect_src / aspect_dst) - dst_maxwidth; + } + + if ((flags & RESIZE_BMP_INCREASE)==0 && + (src_w 0) { + fact = (src_w * FACT_SCALE) / (dst_w + decrement_x); + if ((fact < FACT_SCALE && (flags & RESIZE_BMP_DECREASE)) || /* decrease allowed */ + (fact > FACT_SCALE && (flags & RESIZE_BMP_INCREASE))) /* increase allowed */ + fact_w = fact; + } + + if (dst_h > 0) { + fact = (src_h * FACT_SCALE) / (dst_h + decrement_y); + if ((fact < FACT_SCALE && (flags & RESIZE_BMP_DECREASE)) || /* decrease allowed */ + (fact > FACT_SCALE && (flags & RESIZE_BMP_INCREASE))) /* increase allowed */ + fact_h = fact; + } + + if ((flags & RESIZE_BMP_IGNORE_ASPECT)==0) + { /* keep aspect ratio of source */ + if (fact_wwidth = dst_w; + bm->height = dst_h; + + DEBUGF("read_bmp_file: src=%d/%d, dst=%d/%d max=%d/%d (fact=%d/%d) dec=%d/%d\n", + src_w, src_h, + dst_w, dst_h, + dst_maxwidth, dst_maxheight, + fact_w, fact_h, + decrement_x,decrement_y); + + /* Exit if too big for screen */ + if ((flags & RESIZE_BMP_NONE)==0 && (dst_w > LCD_WIDTH || dst_h > LCD_HEIGHT)) { + DEBUGF("read_bmp_file: error - Bitmap is too big (%d x %d pixels, screen is %d x %d)\n", + dst_w, dst_h, LCD_WIDTH, LCD_HEIGHT); + return -5; + } + + depth = readshort(&bmph.bit_count); + src_padded_width = ((src_w * depth + 31) >> 3) & ~3; /* 4-byte boundary aligned */ + +#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) + if (format == FORMAT_ANY) { + if (depth == 1) + format = FORMAT_MONO; + else + format = FORMAT_NATIVE; + } + bm->format = format; + 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_padded_width = dst_w; + dst_padded_height = (dst_h + 7) >> 3; +# endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ + totalsize = dst_padded_width * dst_padded_height * sizeof(fb_remote_data); + } else +# endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ + { +# if LCD_DEPTH == 2 +# if LCD_PIXELFORMAT == VERTICAL_PACKING + dst_padded_width = dst_w; + dst_padded_height = (dst_h + 3) >> 2; +# else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */ + dst_padded_width = (dst_w + 3) >> 2; + dst_padded_height = dst_h; +# endif /* LCD_PIXELFORMAT */ +# elif LCD_DEPTH == 16 + dst_padded_width = dst_w; + dst_padded_height = dst_h; +# endif /* LCD_DEPTH */ + totalsize = dst_padded_width * dst_padded_height * sizeof(fb_data); + } + } else +#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ + { + dst_padded_width = dst_w; + dst_padded_height = (dst_h + 7) >> 3; + totalsize = dst_padded_width * dst_padded_height; + } + + /* Check if this fits the buffer */ + if (totalsize > maxsize) { + DEBUGF("read_bmp_file: error - Bitmap is too large to fit the supplied buffer: " + "%d bytes.%d:%d\n", (dst_padded_height * dst_padded_width), + totalsize, maxsize); + return -6; + } + + compression = readlong(&bmph.compression); + if (depth <= 8) { + numcolors = readlong(&bmph.clr_used); + if (numcolors == 0) + numcolors = 1 << depth; + } else + numcolors = (compression == 3) ? 3 : 0; + + if (numcolors > 0 && numcolors <= 256) { + if (rb->read(fd, palette, numcolors * sizeof(uint32_t)) + != numcolors * (int)sizeof(uint32_t)) + { + DEBUGF("read_bmp_file: Can't read color palette\n"); + return -7; + } + } + + switch (depth) { + case 16: +#if LCD_DEPTH >= 16 + /* don't dither 16 bit BMP to LCD with same or larger depth */ +#ifdef HAVE_REMOTE_LCD + if (!remote) +#endif + dither = false; +#endif + if (compression == 0) { /* BI_RGB, i.e. 15 bit */ + depth = 15; + break; + } /* else fall through */ + + case 32: + if (compression == 3) { /* BI_BITFIELDS */ + if (!rb->memcmp(palette, bitfields[0], 12)) { /* 15 bit */ + depth = 15; + break; + } + if (!rb->memcmp(palette, bitfields[1], 12) /* 16 bit */ + || !rb->memcmp(palette, bitfields[2], 12)) /* 32 bit */ + { + break; + } + } /* else fall through */ + + default: + if (compression != 0) { /* not BI_RGB */ + DEBUGF("read_bmp_file: Unsupported compression (type %d)\n", + compression); + return -8; + } + break; + } + + /* Search to the beginning of the image data */ + rb->lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET); + + rb->memset(bitmap, 0, totalsize); + +#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 + if (remote) + format |= FORMAT_REMOTE; // set remote flag if it is necessary +#endif + + /* loop to read rows and put them to buffer */ + for (row = src_h - 1; row >= 0; row--) { + /* read one row */ + int dst_y, num_rows = 0; + if (fact_h >= FACT_SCALE) { + /* decrease vertically or just transport the pixels + * -> put only every "fact" row to the dest buffer */ + if ((row % (fact_h / FACT_SCALE)) == 0) { + dst_y = (row * FACT_SCALE) / fact_h - top; + if (dst_y>=0 && dst_y duplicate src-pixel for not existing dst_rows/cols */ + dst_y = MAX(row * FACT_SCALE / fact_h - top,0); + num_rows = MIN((row + 1) * FACT_SCALE / fact_h - top, dst_h)-dst_y; + } + if (num_rows<=0) { + /* if we are not going to process data - just skip reading */ + ret = rb->lseek(fd, src_padded_width, SEEK_CUR ); + continue; + } + ret = rb->read(fd, bmpbuf, src_padded_width); + if (ret != src_padded_width) { + DEBUGF("read_bmp_file: error reading image, read returned: %d " + "expected: %d\n", ret, src_padded_width); + return -9; + } + unsigned data, mask; + unsigned char *p; + uint16_t *p2; + uint32_t *rp; + union rgb_union q0, q1; + + /* convert whole line in-place to XRGB8888 (little endian) */ + rp = (uint32_t *)(bmpbuf + src_w); + switch (depth) { + case 1: + q0.raw = palette[0].raw; + q1.raw = palette[1].raw; + p = (unsigned char*)bmpbuf + ((src_w + 7) >> 3); + mask = 0x80 >> ((src_w + 7) & 7); + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + for (; mask <= 0x80; mask <<= 1) + *(--rp) = (data & mask) ? q1.raw : q0.raw; + mask = 0x01; + } + break; + + case 4: + if (src_w & 1) + rp++; + p = (unsigned char*)bmpbuf + ((src_w + 1) >> 1); + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + *(--rp) = palette[data & 0x0f].raw; + *(--rp) = palette[data >> 4].raw; + } + break; + + case 8: + p = (unsigned char*)bmpbuf + src_w; + while (p > (unsigned char*)bmpbuf) + *(--rp) = palette[*(--p)].raw; + break; + + case 15: + case 16: + p2 = (uint16_t *)bmpbuf + src_w; + while (p2 > (uint16_t *)bmpbuf) { + unsigned component, rgb; + + data = letoh16(*(--p2)); + /* blue */ + component = (data << 3) & 0xf8; +#ifdef ROCKBOX_BIG_ENDIAN + rgb = (component | (component >> 5)) << 8; + /* green */ + data >>= 2; + if (depth == 15) { + component = data & 0xf8; + rgb |= component | (component >> 5); + } else { + data >>= 1; + component = data & 0xfc; + rgb |= component | (component >> 6); + } + /* red */ + data >>= 5; + component = data & 0xf8; + rgb = (rgb << 8) | component | (component >> 5); + *(--rp) = rgb << 8; +#else /* little endian */ + rgb = component | (component >> 5); + /* green */ + data >>= 2; + if (depth == 15) { + component = data & 0xf8; + rgb |= (component | (component >> 5)) << 8; + } else { + data >>= 1; + component = data & 0xfc; + rgb |= (component | (component >> 6)) << 8; + } + /* red */ + data >>= 5; + component = data & 0xf8; + rgb |= (component | (component >> 5)) << 16; + *(--rp) = rgb; +#endif + } + break; + + case 24: + p = (unsigned char*)bmpbuf + 3 * src_w; + while (p > (unsigned char*)bmpbuf) { + data = *(--p); + data = (data << 8) | *(--p); + data = (data << 8) | *(--p); + *(--rp) = htole32(data); + } + break; + + case 32: /* already in desired format */ + break; + } + + /* Convert to destination format */ + while (--num_rows>=0) { + int src_col, dst_x; + if (fact_w >= FACT_SCALE) + { /* decrease horizontally or just transport the pixels */ + for (dst_x = 0; dst_x < dst_w; dst_x++) { + src_col = ((dst_x + left) * fact_w) / FACT_SCALE; + set_pixel(format,bitmap,dither,bmpbuf[src_col],dst_padded_width,dst_x,dst_y); + } + } + else /*if (fact_w < FACT_SCALE)*/ + { /* increase horizontally */ + for (src_col = 0; src_col < src_w; src_col++) { + int num_col; + dst_x = MAX(src_col * FACT_SCALE / fact_w - left,0); + num_col = MIN((src_col + 1) * FACT_SCALE / fact_w - left,dst_w) - dst_x; + q0 = bmpbuf[src_col]; + while (--num_col>=0) { + set_pixel(format,bitmap,dither,q0,dst_padded_width,dst_x,dst_y); + dst_x++; + } + } + } + dst_y++; + } + } + + DEBUGF("read_bmp_file: totalsize=%d, width=%d, height=%d depth=%d compression=%d numcolors=%d\n", + totalsize, dst_w, dst_h, depth, compression, numcolors); + + return totalsize; /* return the used buffer size. */ +} + +/****************************************************************************** + * read_resize_bmp_file() + * + * Reads a BMP from a file puts the data in rockbox format in *bitmap. + * + *****************************************************************************/ +int read_resize_bmp_file(const char* filename, + struct bitmap *bm, + int maxsize, + int format, + int dst_maxwidth, + int dst_maxheight, + int flags, + struct plugin_api* rb) +{ + int fd = rb->open(filename, O_RDONLY); + int res; + /* Exit if file opening failed */ + if (fd < 0) { + DEBUGF("read_resize_bmp_file: can't open '%s', rc: %d\n", filename, fd); + return fd * 10 - 1; + } + res = read_resize_bmp_fd(fd, bm, maxsize, format, dst_maxwidth, dst_maxheight, flags, rb); + rb->close(fd); + return res; +} Index: apps/plugins/lib/bmp.h =================================================================== --- apps/plugins/lib/bmp.h (revision 15825) +++ apps/plugins/lib/bmp.h (working copy) @@ -21,10 +21,38 @@ #include "lcd.h" #include "plugin.h" +#include "recorder/bmp.h" /** * Save bitmap to file */ +#ifdef HAVE_LCD_COLOR int save_bmp_file( char* filename, struct bitmap *bm, struct plugin_api* rb ); +#endif +int read_resize_bmp_fd( int fd, + struct bitmap *bm_out, + int maxsize, + int format, + int dst_maxwidth, /* = 0 */ + int dst_maxheight,/* = 0 */ + int flags, /* BMP_RESIZE_NONE */ + struct plugin_api* rb ); + +int read_resize_bmp_file( const char* filename, + struct bitmap *bm_out, + int maxsize, + int format, + int dst_maxwidth, /* = 0 */ + int dst_maxheight,/* = 0 */ + int flags, /* BMP_RESIZE_NONE */ + struct plugin_api* rb ); + + +#define RESIZE_BMP_NONE 1 +#define RESIZE_BMP_INCREASE 2 +#define RESIZE_BMP_DECREASE 4 +#define RESIZE_BMP_IGNORE_ASPECT 8 +#define RESIZE_BMP_FILL 16 + #endif Index: apps/plugin.c =================================================================== --- apps/plugin.c (revision 15825) +++ apps/plugin.c (working copy) @@ -45,6 +45,7 @@ #include "peakmeter.h" #include "bmp.h" #include "bidi.h" +#include "albumart.h" #endif #ifdef SIMULATOR @@ -525,6 +526,9 @@ file_exists, dir_exists, +#if defined HAVE_ALBUMART + albumart_search_files, +#endif }; int plugin_load(const char* plugin, void* parameter) Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 15825) +++ apps/plugin.h (working copy) @@ -648,7 +648,11 @@ bool (*file_exists)(const char *file); bool (*dir_exists)(const char *path); - +#if defined HAVE_ALBUMART + bool (*plugin_albumart_search_files)( const struct mp3entry *id3, + const char* size_string, + char * buf, int buflen ); +#endif };