Make scaler output truly pluggable, add an 8-bit greyscale output to
pluginlib for use with greylib, and add source for a test scaled bmp
viewer using greylib.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19593 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/buffering.c b/apps/buffering.c
index 6160869..1e643c5 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -861,7 +861,7 @@
     get_albumart_size(bmp);
 
     rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
-                     FORMAT_RESIZE|FORMAT_KEEP_ASPECT);
+                     FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
     return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
 }
 #endif
diff --git a/apps/gui/backdrop.c b/apps/gui/backdrop.c
index 6178894..c95fda9 100644
--- a/apps/gui/backdrop.c
+++ b/apps/gui/backdrop.c
@@ -52,7 +52,7 @@
     /* load the image */
     bm.data=(char*)backdrop_buffer;
     ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
-                        FORMAT_NATIVE | FORMAT_DITHER);
+                        FORMAT_NATIVE | FORMAT_DITHER, NULL);
 
     if ((ret > 0) && (bm.width == LCD_WIDTH) && (bm.height == LCD_HEIGHT))
     {
@@ -114,7 +114,7 @@
     /* load the image */
     bm.data=(char*)backdrop_buffer;
     ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
-                        FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE);
+                        FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE, NULL);
 
     if ((ret > 0) && (bm.width == LCD_REMOTE_WIDTH) && (bm.height == LCD_REMOTE_HEIGHT))
     {
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
index e11c21c..3e1e793 100644
--- a/apps/gui/icon.c
+++ b/apps/gui/icon.c
@@ -222,7 +222,7 @@
         char path[MAX_PATH];
         
         snprintf(path, sizeof(path), "%s/%s.bmp", ICON_DIR, filename);
-        size_read = read_bmp_file(path, bmp, IMG_BUFSIZE, bmpformat);
+        size_read = read_bmp_file(path, bmp, IMG_BUFSIZE, bmpformat, NULL);
         if (size_read > 0)
         {
             *loaded_ok = true;
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index 307d0bb..acf161b 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -416,7 +416,7 @@
 
     int ret = read_bmp_file(filename, bm,
                             wps_data->img_buf_free,
-                            format);
+                            format,NULL);
 
     if (ret > 0)
     {
diff --git a/apps/plugin.h b/apps/plugin.h
index 20e3a71..81c0696 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -132,12 +132,12 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 130
+#define PLUGIN_API_VERSION 131
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
    new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 130
+#define PLUGIN_MIN_API_VERSION 131
 
 /* plugin return codes */
 enum plugin_status {
@@ -714,7 +714,7 @@
 #endif
 #ifdef HAVE_LCD_BITMAP
     int (*read_bmp_file)(const char* filename, struct bitmap *bm, int maxsize,
-                         int format);
+                         int format, const struct custom_format *cformat);
     void (*screen_dump_set_hook)(void (*hook)(int fh));
 #endif
     int (*show_logo)(void);
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index 750d149..09a4476 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -92,6 +92,7 @@
 test_scanrate,apps
 test_touchscreen,apps
 test_viewports,apps
+test_greylib_bitmap_scale,viewers
 text_editor,apps
 vbrfix,viewers
 video,viewers
diff --git a/apps/plugins/lib/grey.h b/apps/plugins/lib/grey.h
index 8f8de9d..8c9d40a 100644
--- a/apps/plugins/lib/grey.h
+++ b/apps/plugins/lib/grey.h
@@ -106,6 +106,7 @@
                               int stride, int x, int y, int width, int height);
 void grey_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
                          int height);
+extern const struct custom_format format_grey;
 
 /* Text */
 void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str);
diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c
index e9812b6..51d340d 100644
--- a/apps/plugins/lib/grey_draw.c
+++ b/apps/plugins/lib/grey_draw.c
@@ -669,3 +669,22 @@
 {
     grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
 }
+
+static void output_row_grey(uint32_t row, void * row_in, struct scaler_context *ctx)
+{
+    int col;
+    uint32_t *qp = (uint32_t*)row_in;
+    uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
+    for (col = 0; col < ctx->bm->width; col++)
+        *dest++ = ((*qp++) + ctx->round) * (uint64_t)ctx->divisor >> 32;
+}
+
+static unsigned int get_size_grey(struct bitmap *bm)
+{
+    return bm->width * bm->height;
+}
+
+const struct custom_format format_grey = {
+    .output_row = output_row_grey,
+    .get_size = get_size_grey
+};
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index 150d882..0dd9f92 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -636,7 +636,7 @@
         input_bmp.data = (char *)input_bmp_buffer;
         ret = rb->read_bmp_file(arlbumart_file, &input_bmp,
                                 sizeof(fb_data)*MAX_IMG_WIDTH*MAX_IMG_HEIGHT,
-                                FORMAT_NATIVE);
+                                FORMAT_NATIVE, NULL);
         if (ret <= 0) {
             rb->splash(HZ, "Could not read bmp");
             continue; /* skip missing/broken files */
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index 300821b..40d1910 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -2967,7 +2967,7 @@
 
     bm.data = (char*)save_buffer;
     ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ),
-                             FORMAT_NATIVE );
+                             FORMAT_NATIVE, NULL );
 
     if((bm.width > COLS ) || ( bm.height > ROWS ))
         return -1;
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c
index fa9e093..8a607c9 100644
--- a/apps/plugins/sliding_puzzle.c
+++ b/apps/plugins/sliding_puzzle.c
@@ -340,7 +340,8 @@
 
         rc = rb->read_bmp_file( filename, &main_bitmap,
                                 sizeof(img_buf),
-                                FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER);
+                                FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER,
+                                NULL);
         if( rc > 0 )
         {
             puzzle_bmp_ptr = (const fb_data *)img_buf;
diff --git a/apps/plugins/test_resize.c b/apps/plugins/test_resize.c
index b0ef787..a608005 100644
--- a/apps/plugins/test_resize.c
+++ b/apps/plugins/test_resize.c
@@ -78,7 +78,7 @@
     output_bmp.data = (char*)output_bmp_data;
 
     int ret = rb->read_bmp_file("/test.bmp", &input_bmp, sizeof(input_bmp_data),
-                                FORMAT_NATIVE);
+                                FORMAT_NATIVE, NULL);
 
     if (ret < 0) {
         rb->splash(HZ, "Could not load /test.bmp");
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index e2babf6..2ec8fe9 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -25,6 +25,7 @@
 wav,viewers/wavplay,9
 wav,viewers/wavview,10
 wav,viewers/test_codec,-
+bmp,viewers/test_greylib_bitmap_scale,-
 bmp,apps/rockpaint,11
 bmp,games/sliding_puzzle,11
 mpg,viewers/mpegplayer,4
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index cc57464..86c057a 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -147,7 +147,8 @@
 int read_bmp_file(const char* filename,
                   struct bitmap *bm,
                   int maxsize,
-                  int format)
+                  int format,
+                  const struct custom_format *cformat)
 {
     int fd, ret;
     fd = open(filename, O_RDONLY);
@@ -161,7 +162,7 @@
     BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
            filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
            !!(format & FORMAT_KEEP_ASPECT));
-    ret = read_bmp_fd(fd, bm, maxsize, format);
+    ret = read_bmp_fd(fd, bm, maxsize, format, cformat);
     close(fd);
     return ret;
 }
@@ -349,7 +350,8 @@
 int read_bmp_fd(int fd,
                 struct bitmap *bm,
                 int maxsize,
-                int format)
+                int format,
+                const struct custom_format *cformat)
 {
     struct bmp_header bmph;
     int padded_width;
@@ -473,7 +475,10 @@
         rset.rowstop = -1;
     }
 
-    totalsize = BM_SIZE(bm->width,bm->height,format,remote);
+    if (cformat)
+        totalsize = cformat->get_size(bm);
+    else
+        totalsize = BM_SIZE(bm->width,bm->height,format,remote);
 
     /* Check if this fits the buffer */
     if (totalsize > maxsize) {
@@ -565,10 +570,15 @@
     };
 
 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
-    if (resize)
-        return resize_on_load(bm, dither, &src_dim, &rset,
-                               bitmap + totalsize, maxsize - totalsize,
-                               store_part_bmp, &ba);
+    if (resize || cformat)
+    {
+        if (resize_on_load(bm, dither, &src_dim, &rset,
+                           bitmap + totalsize, maxsize - totalsize,
+                           cformat, store_part_bmp, &ba))
+            return totalsize;
+        else
+            return 0;
+    }
 
     int fb_width = BM_WIDTH(bm->width,bm->format,remote);
 #endif /* LCD_DEPTH */
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h
index 273e178..c53f295 100644
--- a/apps/recorder/bmp.h
+++ b/apps/recorder/bmp.h
@@ -24,6 +24,7 @@
 #include "config.h"
 #include "lcd.h"
 #include "inttypes.h"
+#include "resize.h"
 #ifdef HAVE_REMOTE_LCD
 #include "lcd-remote.h"
 #endif
@@ -202,10 +203,12 @@
 int read_bmp_file(const char* filename,
                   struct bitmap *bm,
                   int maxsize,
-                  int format);
+                  int format,
+                  const struct custom_format *cformat);
 
 int read_bmp_fd(int fd,
                 struct bitmap *bm,
                 int maxsize,
-                int format);
+                int format,
+                const struct custom_format *cformat);
 #endif
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index 3c1d34f..658cdd8 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -114,23 +114,6 @@
         return false; \
 }
 
-/* struct which containers various parameters shared between vertical scaler,
-   horizontal scaler, and row output
-*/
-struct scaler_context {
-    uint32_t divisor;
-    uint32_t round;
-    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 inline void scale_h_area_setup(struct scaler_context *ctx)
 {
@@ -610,6 +593,7 @@
 
 int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
                    struct rowset *rset, unsigned char *buf, unsigned int len,
+                   const struct custom_format *format,
                    struct img_part* (*store_part)(void *args),
                    void *args)
 {
@@ -669,7 +653,10 @@
     ctx.bm = bm;
     ctx.src = src;
     ctx.dither = dither;
-    ctx.output_row = output_row_native;
+    if (format)
+        ctx.output_row = format->output_row;
+    else
+        ctx.output_row = output_row_native;
 #ifdef HAVE_UPSCALER
     if (sw > dw)
     {
@@ -693,5 +680,5 @@
     cpu_boost(false);
     if (!ret)
         return 0;
-    return BM_SIZE(bm->width,bm->height,bm->format,0);
+    return 1;
 }
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h
index 4518307..ca7e632 100644
--- a/apps/recorder/resize.h
+++ b/apps/recorder/resize.h
@@ -20,7 +20,6 @@
  ****************************************************************************/
 #ifndef _RESIZE_H_
 #define _RESIZE_H_
-
 #include "config.h"
 #include "lcd.h"
 #include "inttypes.h"
@@ -65,11 +64,35 @@
 };
 #endif
 
+/* struct which contains various parameters shared between vertical scaler,
+   horizontal scaler, and row output
+*/
+struct scaler_context {
+    uint32_t divisor;
+    uint32_t round;
+    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);
+};
+
+struct custom_format {
+    void (*output_row)(uint32_t,void*,struct scaler_context*);
+    unsigned int (*get_size)(struct bitmap *bm);
+};
+
+struct rowset;
 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,
+                   const struct custom_format *cformat,
                    struct img_part* (*store_part)(void *args),
                    void *args);
 #endif /* _RESIZE_H_ */