More color adjustments. Better translation to and from native colors with even distribution of levels. Macros for extracting native depth components and packing them.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11227 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/gui/color_picker.c b/apps/gui/color_picker.c
index 32b392c..08c05d9 100644
--- a/apps/gui/color_picker.c
+++ b/apps/gui/color_picker.c
@@ -56,8 +56,7 @@
 /* list of primary colors */
 #define SB_PRIM 0
 #define SB_FILL 1
-#define SB_MAX  2
-static const unsigned short prim_rgb[][3] =
+static const fb_data prim_rgb[][3] =
 {
     /* Foreground colors for sliders */
     {
@@ -71,39 +70,32 @@
         LCD_RGBPACK(  0,  85,   0),
         LCD_RGBPACK(  0,   0,  85),
     },
-    /* maximum values for components */
-    {
-        LCD_MAX_RED,
-        LCD_MAX_GREEN,
-        LCD_MAX_BLUE
-    }
+};
+
+/* maximum values for components */
+static const unsigned char rgb_max[3] =
+{
+    LCD_MAX_RED,
+    LCD_MAX_GREEN,
+    LCD_MAX_BLUE
 };
 
 /* Unpacks the color value into native rgb values and 24 bit rgb values */
 static void unpack_rgb(struct rgb_pick *rgb)
 {
-    unsigned color = rgb->color;
-#if LCD_PIXELFORMAT == RGB565SWAPPED
-    color = swap16(color);
-#endif
+    unsigned color = _LCD_UNSWAP_COLOR(rgb->color);
     rgb->red   = _RGB_UNPACK_RED(color);
     rgb->green = _RGB_UNPACK_GREEN(color);
     rgb->blue  = _RGB_UNPACK_BLUE(color);
-    rgb->r     = (color & 0xf800) >> 11;
-    rgb->g     = (color & 0x07e0) >> 5;
-    rgb->b     = (color & 0x001f);
+    rgb->r     = _RGB_UNPACK_RED_LCD(color);
+    rgb->g     = _RGB_UNPACK_GREEN_LCD(color);
+    rgb->b     = _RGB_UNPACK_BLUE_LCD(color);
 }
 
 /* Packs the native rgb colors into a color value */
-static void pack_rgb(struct rgb_pick *rgb)
+static inline void pack_rgb(struct rgb_pick *rgb)
 {
-    unsigned color = (rgb->r & 0x1f) << 11 |
-                     (rgb->g & 0x3f) << 5 |
-                     (rgb->b & 0x1f);
-#if LCD_PIXELFORMAT == RGB565SWAPPED
-    color = swap16(color);
-#endif
-    rgb->color = color;
+    rgb->color = LCD_RGBPACK_LCD(rgb->r, rgb->g, rgb->b);
 }
 
 /* Returns LCD_BLACK if the color is above a threshold brightness
@@ -265,7 +257,7 @@
                            text_top + display->char_height / 4,
                            slider_width,
                            display->char_height / 2,
-                           prim_rgb[SB_MAX][i],
+                           rgb_max[i],
                            0,
                            rgb->rgb_val[i],
                            sb_flags);
@@ -343,22 +335,29 @@
  color is a pointer to the colour (in native format) to modify
  set banned_color to -1 to allow all
  ***********/
-bool set_color(struct screen *display, char *title, int* color, int banned_color)
+bool set_color(struct screen *display, char *title, unsigned *color,
+               unsigned banned_color)
 {
-    int exit = 0, button, slider = 0;
-    int i;
+    int exit = 0, slider = 0;
     struct rgb_pick rgb;
-    (void)display;
 
     rgb.color = *color;
 
     while (!exit)
     {
+        int button;
+
         unpack_rgb(&rgb);
 
-        FOR_NB_SCREENS(i)
+        if (display != NULL)
         {
-            draw_screen(&screens[i], title, &rgb, slider);
+            draw_screen(display, title, &rgb, slider);
+        }
+        else
+        {
+            int i;
+            FOR_NB_SCREENS(i)
+                draw_screen(&screens[i], title, &rgb, slider);
         }
 
         button = get_action(CONTEXT_SETTINGS_COLOURCHOOSER, TIMEOUT_BLOCK);
@@ -377,7 +376,7 @@
 
             case ACTION_SETTINGS_INC:
             case ACTION_SETTINGS_INCREPEAT:
-                if (rgb.rgb_val[slider] < prim_rgb[SB_MAX][slider])
+                if (rgb.rgb_val[slider] < rgb_max[slider])
                     rgb.rgb_val[slider]++;
                 pack_rgb(&rgb);
                 break;
@@ -390,7 +389,8 @@
                 break;
 
             case ACTION_STD_OK:
-                if (banned_color != -1 && (unsigned)banned_color == rgb.color)
+                if (banned_color != (unsigned)-1 &&
+                    banned_color == rgb.color)
                 {
                     gui_syncsplash(HZ*2, true, str(LANG_COLOR_UNACCEPTABLE));
                     break;
diff --git a/apps/gui/color_picker.h b/apps/gui/color_picker.h
index f520083..3bd2325 100644
--- a/apps/gui/color_picker.h
+++ b/apps/gui/color_picker.h
@@ -20,6 +20,7 @@
 
 #ifdef HAVE_LCD_COLOR /* this file is a bit useless on non color lcds.. */
 
-bool set_color(struct screen *display,char *title, int* color, int banned_color);
+bool set_color(struct screen *display, char *title, unsigned *color,
+               unsigned banned_color);
 
 #endif
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index 19376bf..3044e8e 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -63,11 +63,11 @@
 } STRUCT_PACKED;
 
 struct rgb_quad { /* Little endian */
-  unsigned char blue; 
-  unsigned char green; 
+  unsigned char blue;
+  unsigned char green;
   unsigned char red;
   unsigned char reserved;
-} STRUCT_PACKED; 
+} STRUCT_PACKED;
 
 /* big endian functions */
 static short readshort(short *value) {
@@ -96,8 +96,8 @@
 }
 
 #if LCD_DEPTH == 16
-/* Cheapo 24 -> 16 bit dither */
-static unsigned short dither_24_to_16(struct rgb_quad rgb, int row, int col)
+/* 24 -> lcd depth dither */
+static fb_data dither_24_to_lcd(struct rgb_quad rgb, int row, int col)
 {
     static const unsigned char dith[][16] =
     {
@@ -115,22 +115,17 @@
         },
     };
 
-    const int elm = (row & 3) + ((col & 3) << 2);
-    unsigned short color;
+    const unsigned elm = (row & 3) + ((col & 3) << 2);
+    unsigned b, g, r;
 
-    unsigned b = ((unsigned)rgb.blue  + dith[0][elm]) >> 3;
-    if (b > 0x1f) b = 0x1f;
-    unsigned g = ((unsigned)rgb.green + dith[1][elm]) >> 2;
-    if (g > 0x3f) g = 0x3f;
-    unsigned r = ((unsigned)rgb.red   + dith[0][elm]) >> 3;
-    if (r > 0x1f) r = 0x1f;
+    b = ((unsigned)rgb.blue  + dith[0][elm]) >> (8-LCD_BLUE_BITS);
+    if (b > LCD_MAX_BLUE)  b = LCD_MAX_BLUE;
+    g = ((unsigned)rgb.green + dith[1][elm]) >> (8-LCD_GREEN_BITS);
+    if (g > LCD_MAX_GREEN) g = LCD_MAX_GREEN;
+    r = ((unsigned)rgb.red   + dith[0][elm]) >> (8-LCD_RED_BITS);
+    if (r > LCD_MAX_RED)   r = LCD_MAX_RED;
 
-    color = (unsigned short)(b | (g << 5) | (r << 11));
-
-#if LCD_PIXELFORMAT == RGB565SWAPPED
-    color = swap16(color);
-#endif
-    return color;
+    return LCD_RGBPACK_LCD(r, g, b);
 }
 #endif /* LCD_DEPTH == 16 */
 
@@ -179,7 +174,7 @@
     /* Exit if file opening failed */
     if (fd < 0) {
         DEBUGF("error - can't open '%s' open returned: %d\n", filename, fd);
-        return (fd * 10) - 1; 
+        return (fd * 10) - 1;
     }
 
     /* read fileheader */
@@ -188,7 +183,7 @@
         close(fd);
         return (ret * 10 - 2);
     }
-    
+
     if(ret != sizeof(struct Fileheader)) {
         DEBUGF("error - can't read Fileheader structure.");
         close(fd);
@@ -250,7 +245,7 @@
     }
 
     /* Check if this fits the buffer */
-    
+
     if (totalsize > maxsize) {
         DEBUGF("error - Bitmap is too large to fit the supplied buffer: "
                "%d bytes.\n", (PaddedHeight * dst_width));
@@ -278,7 +273,7 @@
         if(brightness(palette[0]) < brightness(palette[1]))
            invert_pixel = 1;
     }
-    
+
     /* Search to the beginning of the image data */
     lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET);
 
@@ -286,15 +281,15 @@
     if(format == FORMAT_NATIVE)
         memset(bitmap, 0, totalsize);
 #endif
-    
+
 #if LCD_DEPTH > 1
     fb_data *dest = (fb_data *)bitmap;
 #endif
-    
+
     /* loop to read rows and put them to buffer */
     for (row = 0; row < height; row++) {
         unsigned char *p;
-        
+
         /* read one row */
         ret = read(fd, bmpbuf, PaddedWidth);
         if (ret != PaddedWidth) {
@@ -326,7 +321,7 @@
                 /* Mono -> 2gray (iriver H1xx) */
                 for (col = 0; col < width; col++) {
                     ret = getpix(col, bmpbuf) ^ invert_pixel;
-                    
+
                     if (ret)
                         dest[((height - row - 1)/4) * width + col] |=
                             0xC0 >> (2 * (~(height - row - 1) & 3));
@@ -337,7 +332,7 @@
                 /* Mono -> 2gray (ipod) */
                 for (col = 0; col < width; col++) {
                     ret = getpix(col, bmpbuf) ^ invert_pixel;
-                    
+
                     if (ret)
                         dest[(height - row - 1) * dst_width + col/4] |=
                             0xC0 >> (2 * (col & 3));
@@ -409,8 +404,8 @@
                 for (col = 0; col < width; col++, p++) {
                     struct rgb_quad rgb = palette[*p];
                     dest[width * (height - row - 1) + col] = dither ?
-                        dither_24_to_16(rgb, row, col) :
-                        LCD_RGBPACK(rgb.red, rgb.green, rgb.blue);
+                        dither_24_to_lcd(rgb, row, col) :
+                        (fb_data)LCD_RGBPACK(rgb.red, rgb.green, rgb.blue);
                 }
             }
 #endif
@@ -474,8 +469,8 @@
                 /* RGB24 -> RGB16 */
                 for (col = 0; col < width; col++, p += 3) {
                     dest[width * (height - row - 1) + col] = dither ?
-                        dither_24_to_16(*(struct rgb_quad *)p, row, col) :
-                        LCD_RGBPACK(p[2], p[1], p[0]);
+                        dither_24_to_lcd(*(struct rgb_quad *)p, row, col) :
+                        (fb_data)LCD_RGBPACK(p[2], p[1], p[0]);
                 }
             }
 #endif
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 35bdccb..eabe153 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -409,7 +409,7 @@
 {
     bool res;
 
-    res = set_color(&screens[SCREEN_MAIN],str(LANG_FOREGROUND_COLOR),
+    res = set_color(NULL,str(LANG_FOREGROUND_COLOR),
                     &global_settings.fg_color,global_settings.bg_color);
 
     screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
@@ -421,7 +421,7 @@
 {
     bool res;
 
-    res = set_color(&screens[SCREEN_MAIN],str(LANG_BACKGROUND_COLOR),
+    res = set_color(NULL,str(LANG_BACKGROUND_COLOR),
                     &global_settings.bg_color,global_settings.fg_color);
 
     screens[SCREEN_MAIN].set_background(global_settings.bg_color);
@@ -1699,7 +1699,7 @@
 
 static bool unplug_autoresume(void)
 {
-    return set_bool( str(LANG_UNPLUG_DISABLE_AUTORESUME), 
+    return set_bool( str(LANG_UNPLUG_DISABLE_AUTORESUME),
                     &global_settings.unplug_autoresume );
 }
 
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index 4949f51..22ae5a3 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -161,37 +161,58 @@
 #endif
 
 #ifdef HAVE_LCD_COLOR
-#if LCD_DEPTH == 16
+#if LCD_PIXELFORMAT == RGB565 || LCD_PIXELFORMAT == RGB565SWAPPED
 #define LCD_MAX_RED    31
 #define LCD_MAX_GREEN  63
 #define LCD_MAX_BLUE   31
-#define _RGB_UNPACK_RED(x)   ((((x) >> 8) & 0xf8) | ((x) >> 13))
-#define _RGB_UNPACK_GREEN(x) ((((x) >> 3) & 0xfc) | (((x) >> 9) & 0x03))
-#define _RGB_UNPACK_BLUE(x)  ((((x) << 3) & 0xf8) | (((x) >> 2) & 0x07))
-#define _RGBPACK(r, g, b) ( ((((r) * (31*257) + (127*257)) >> 16) << 11) \
-                           |((((g) * (63*257) + (127*257)) >> 16) << 5) \
-                           | (((b) * (31*257) + (127*257)) >> 16))
-/* Note: ((x * 257) >> 16) almost equals (x / 255), but it avoids the division,
- * so it's faster when the macro is used for variable r, g, b in the source. */
+#define LCD_RED_BITS   5
+#define LCD_GREEN_BITS 6
+#define LCD_BLUE_BITS  5
+
+/* pack/unpack native RGB values */
+#define _RGBPACK_LCD(r, g, b)    ( ((r) << 11) | ((g) << 5) | (b) )
+#define _RGB_UNPACK_RED_LCD(x)   ( (((x) >> 11)       ) )
+#define _RGB_UNPACK_GREEN_LCD(x) ( (((x) >>  5) & 0x3f) )
+#define _RGB_UNPACK_BLUE_LCD(x)  ( (((x)      ) & 0x1f) )
+
+/* pack/unpack 24-bit RGB values */
+#define _RGBPACK(r, g, b)    _RGBPACK_LCD((r) >> 3, (g) >> 2, (b) >> 3)
+#define _RGB_UNPACK_RED(x)   ( (((x) >> 8) & 0xf8) | (((x) >> 11) & 0x07) )
+#define _RGB_UNPACK_GREEN(x) ( (((x) >> 3) & 0xfc) | (((x) >>  5) & 0x03) )
+#define _RGB_UNPACK_BLUE(x)  ( (((x) << 3) & 0xf8) | (((x)      ) & 0x07) )
+
 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
-#define LCD_RGBPACK(r, g, b) ( ((_RGBPACK((r), (g), (b)) & 0xff00) >> 8) \
-                              |((_RGBPACK((r), (g), (b)) & 0x00ff) << 8))
-#define RGB_UNPACK_RED(x)   _RGB_UNPACK_RED(swap16(x))
-#define RGB_UNPACK_GREEN(x) _RGB_UNPACK_GREEN(swap16(x))
-#define RGB_UNPACK_BLUE(x)  _RGB_UNPACK_BLUE(swap16(x))
+/* RGB3553 */
+#define _LCD_UNSWAP_COLOR(x)     swap16(x)
+#define LCD_RGBPACK_LCD(r, g, b) ( (((r) <<   3)      ) | \
+                                   (((g) >>   3)      ) | \
+                                   (((g) & 0x07) << 13) | \
+                                   (((b) <<   8)      ) )
+#define LCD_RGBPACK(r, g, b)     ( (((r) >>   3) <<  3) | \
+                                   (((g) >>   5)      ) | \
+                                   (((g) & 0x1c) << 11) | \
+                                   (((b) >>   3) <<  8) )
+/* swap color once - not currenly used in static inits */
+#define _SWAPUNPACK(x, _unp_) \
+    ({ typeof (x) _x_ = swap16(x); _unp_(_x_); })
+#define RGB_UNPACK_RED(x)        _SWAPUNPACK((x), _RGB_UNPACK_RED)
+#define RGB_UNPACK_GREEN(x)      _SWAPUNPACK((x), _RGB_UNPACK_GREEN)
+#define RGB_UNPACK_BLUE(x)       _SWAPUNPACK((x), _RGB_UNPACK_BLUE)
+#define RGB_UNPACK_RED_LCD(x)    _SWAPUNPACK((x), _RGB_UNPACK_RED_LCD)
+#define RGB_UNPACK_GREEN_LCD(x)  _SWAPUNPACK((x), _RGB_UNPACK_GREEN_LCD)
+#define RGB_UNPACK_BLUE_LCD(x)   _SWAPUNPACK((x), _RGB_UNPACK_BLUE_LCD)
 #else
-#define LCD_RGBPACK(r, g, b) _RGBPACK((r), (g), (b))
-#define RGB_UNPACK_RED(x)   _RGB_UNPACK_RED(x)
-#define RGB_UNPACK_GREEN(x) _RGB_UNPACK_GREEN(x)
-#define RGB_UNPACK_BLUE(x)  _RGB_UNPACK_BLUE(x)
+/* RGB565 */
+#define _LCD_UNSWAP_COLOR(x)     (x)
+#define LCD_RGBPACK(r, g, b)     _RGBPACK((r), (g), (b))
+#define LCD_RGBPACK_LCD(r, g, b) _RGBPACK_LCD((r), (g), (b))
+#define RGB_UNPACK_RED(x)        _RGB_UNPACK_RED(x)
+#define RGB_UNPACK_GREEN(x)      _RGB_UNPACK_GREEN(x)
+#define RGB_UNPACK_BLUE(x)       _RGB_UNPACK_BLUE(x)
+#define RGB_UNPACK_RED_LCD(x)    _RGB_UNPACK_RED(x)
+#define RGB_UNPACK_GREEN_LCD(x)  _RGB_UNPACK_GREEN(x)
+#define RGB_UNPACK_BLUE_LCD(x)   _RGB_UNPACK_BLUE(x)
 #endif
-#elif LCD_DEPTH == 18
-#define LCD_MAX_RED    63
-#define LCD_MAX_GREEN  63
-#define LCD_MAX_BLUE   63
-#define LCD_RGBPACK(r, g, b) ( ((((r) * (63*257) + (127*257)) >> 16) << 12) \
-                              |((((g) * (63*257) + (127*257)) >> 16) << 6) \
-                              | (((b) * (63*257) + (127*257)) >> 16))
 #else
 /* other colour depths */
 #endif