diff options
Diffstat (limited to 'apps/plugins/lib')
| -rw-r--r-- | apps/plugins/lib/SOURCES | 4 | ||||
| -rw-r--r-- | apps/plugins/lib/grey.h | 166 | ||||
| -rw-r--r-- | apps/plugins/lib/grey_core.c | 767 | ||||
| -rw-r--r-- | apps/plugins/lib/grey_draw.c | 681 | ||||
| -rw-r--r-- | apps/plugins/lib/grey_parm.c | 116 | ||||
| -rw-r--r-- | apps/plugins/lib/grey_scroll.c | 358 |
6 files changed, 2092 insertions, 0 deletions
diff --git a/apps/plugins/lib/SOURCES b/apps/plugins/lib/SOURCES index f671184..5433f7e 100644 --- a/apps/plugins/lib/SOURCES +++ b/apps/plugins/lib/SOURCES @@ -8,6 +8,10 @@ gray_core.c gray_draw.c gray_parm.c gray_scroll.c +grey_core.c +grey_draw.c +grey_parm.c +grey_scroll.c #endif highscore.c #ifndef SIMULATOR diff --git a/apps/plugins/lib/grey.h b/apps/plugins/lib/grey.h new file mode 100644 index 0000000..136794b --- /dev/null +++ b/apps/plugins/lib/grey.h @@ -0,0 +1,166 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* New greyscale framework +* +* This is a generic framework to display 129 shades of grey on low-depth +* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins. +* +* Copyright (C) 2008 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#ifndef __GREY_H__ +#define __GREY_H__ + +#include "plugin.h" + +#if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH < 4) + +#define GREY_BRIGHTNESS(y) (y) + +#define GREY_BLACK GREY_BRIGHTNESS(0) +#define GREY_DARKGRAY GREY_BRIGHTNESS(85) +#define GREY_LIGHTGRAY GREY_BRIGHTNESS(170) +#define GREY_WHITE GREY_BRIGHTNESS(255) + +/* Library initialisation and release */ +bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size, + bool buffered, int width, int height, long *buf_taken); +void grey_release(void); + +/* Special functions */ +void grey_show(bool enable); +void grey_deferred_lcd_update(void); + +/* Update functions */ +void grey_update(void); +void grey_update_rect(int x, int y, int width, int height); + +/* Parameter handling */ +void grey_set_position(int x, int y); +void grey_set_drawmode(int mode); +int grey_get_drawmode(void); +void grey_set_foreground(unsigned brightness); +unsigned grey_get_foreground(void); +void grey_set_background(unsigned brightness); +unsigned grey_get_background(void); +void grey_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness); +void grey_setfont(int newfont); +int grey_getstringsize(const unsigned char *str, int *w, int *h); + +/* Whole display */ +void grey_clear_display(void); +void grey_ub_clear_display(void); + +/* Pixel */ +void grey_drawpixel(int x, int y); + +/* Lines */ +void grey_drawline(int x1, int y1, int x2, int y2); +void grey_hline(int x1, int x2, int y); +void grey_vline(int x, int y1, int y2); +void grey_drawrect(int x, int y, int nx, int ny); + +/* Filled primitives */ +void grey_fillrect(int x, int y, int nx, int ny); +void grey_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3); + +/* Bitmaps */ +void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height); +void grey_mono_bitmap(const unsigned char *src, int x, int y, int width, + int height); +void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height); +void grey_gray_bitmap(const unsigned char *src, int x, int y, int width, + int height); +void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, + 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); + +/* Text */ +void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str); +void grey_putsxy(int x, int y, const unsigned char *str); + +/* Scrolling */ +void grey_scroll_left(int count); +void grey_scroll_right(int count); +void grey_scroll_up(int count); +void grey_scroll_down(int count); +void grey_ub_scroll_left(int count); +void grey_ub_scroll_right(int count); +void grey_ub_scroll_up(int count); +void grey_ub_scroll_down(int count); + +/*** Internal stuff ***/ + +/* flag definitions */ +#define _GREY_RUNNING 0x0001 /* greyscale overlay is running */ +#define _GREY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */ + +/* fast unsigned multiplication (16x16bit->32bit or 32x32bit->32bit, + * whichever is faster for the architecture) */ +#ifdef CPU_ARM +#define _GREY_MULUQ(a, b) ((uint32_t) (((uint32_t) (a)) * ((uint32_t) (b)))) +#else +#define _GREY_MULUQ(a, b) ((uint32_t) (((uint16_t) (a)) * ((uint16_t) (b)))) +#endif + +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING +#define _GREY_X_ADVANCE sizeof(struct grey_data) +#else +#if LCD_DEPTH == 1 +#define _GREY_X_ADVANCE (8*sizeof(struct grey_data)) +#elif LCD_DEPTH == 2 +#define _GREY_X_ADVANCE (4*sizeof(struct grey_data)) +#endif +#endif /* LCD_PIXELFORMAT */ + +/* The greyscale buffer management structure */ +struct _grey_info +{ + int x; + int y; + int width; + int height; +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + int bx; /* 8-pixel units */ + int bwidth; /* 8-pixel units */ +#else /* vertical packing */ + int by; /* 4-pixel or 8-pixel units */ + int bheight; /* 4-pixel or 8-pixel units */ +#endif + unsigned long flags; /* various flags, see #defines */ +#ifndef SIMULATOR + struct grey_data *data; /* start of greyscale display data */ +#endif + unsigned char *buffer; /* start of chunky pixel buffer (for buffered mode) */ + unsigned char gvalue[256]; /* calculated brightness -> greyvalue table */ + int fg_val; /* current foreground value */ + int bg_val; /* current background value */ + int fg_brightness; /* current foreground brightness */ + int bg_brightness; /* current background brightness */ + int drawmode; /* current draw mode */ + int curfont; /* current selected font */ +}; + +/* Global variables */ +extern struct plugin_api *_grey_rb; +extern struct _grey_info _grey_info; + +#endif /* HAVE_LCD_BITMAP && (LCD_DEPTH < 4) */ +#endif /* __GREY_H__ */ diff --git a/apps/plugins/lib/grey_core.c b/apps/plugins/lib/grey_core.c new file mode 100644 index 0000000..b3ab640 --- /dev/null +++ b/apps/plugins/lib/grey_core.c @@ -0,0 +1,767 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* New greyscale framework +* Core & miscellaneous functions +* +* This is a generic framework to display 129 shades of grey on low-depth +* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins. +* +* Copyright (C) 2008 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include "plugin.h" +#include "grey.h" + +#if defined(CPU_PP) && defined(HAVE_ADJUSTABLE_CPU_FREQ) +#define NEED_BOOST +#endif + +/* Global variables */ +struct plugin_api *_grey_rb = NULL; /* global api struct pointer */ +struct _grey_info _grey_info; /* global info structure */ + +#ifndef SIMULATOR + +#if CONFIG_LCD == LCD_SSD1815 || CONFIG_LCD == LCD_IFP7XX +/* measured and interpolated curve */ +/* TODO: check for iFP */ +static const unsigned char lcdlinear[256] = { + 0, 3, 5, 8, 11, 13, 16, 18, + 21, 23, 26, 28, 31, 33, 36, 38, + 40, 42, 45, 47, 49, 51, 53, 55, + 57, 59, 60, 62, 64, 66, 67, 69, + 70, 72, 73, 74, 76, 77, 78, 79, + 81, 82, 83, 84, 85, 86, 87, 88, + 88, 89, 90, 91, 92, 92, 93, 94, + 95, 95, 96, 97, 97, 98, 99, 99, + 100, 101, 102, 102, 103, 104, 104, 105, + 106, 106, 107, 107, 108, 109, 109, 110, + 111, 111, 112, 113, 113, 114, 114, 115, + 116, 116, 117, 117, 118, 119, 119, 120, + 120, 121, 121, 122, 122, 123, 123, 124, + 124, 125, 125, 126, 126, 127, 127, 128, + 128, 128, 129, 129, 130, 130, 131, 131, + 132, 132, 133, 133, 133, 134, 134, 135, + 135, 136, 136, 137, 137, 138, 138, 138, + 139, 139, 140, 140, 141, 141, 142, 142, + 143, 143, 144, 144, 145, 145, 146, 146, + 147, 147, 148, 148, 148, 149, 149, 150, + 150, 151, 151, 152, 152, 153, 153, 153, + 154, 154, 155, 155, 156, 156, 157, 157, + 158, 158, 158, 159, 159, 160, 160, 161, + 161, 162, 162, 163, 163, 164, 164, 165, + 165, 166, 167, 167, 168, 168, 169, 169, + 170, 171, 171, 172, 173, 173, 174, 175, + 176, 176, 177, 178, 179, 180, 181, 181, + 182, 183, 184, 185, 186, 188, 189, 190, + 191, 192, 194, 195, 196, 198, 199, 201, + 202, 204, 205, 207, 209, 211, 213, 215, + 217, 219, 222, 224, 226, 229, 231, 234, + 236, 239, 242, 244, 247, 250, 252, 255 +}; +#elif CONFIG_LCD == LCD_S1D15E06 +/* measured and interpolated curve */ +static const unsigned char lcdlinear[256] = { + 0, 5, 11, 16, 21, 27, 32, 37, + 42, 47, 51, 56, 60, 64, 68, 72, + 75, 78, 81, 84, 87, 89, 91, 93, + 95, 96, 98, 99, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 111, + 112, 113, 113, 114, 115, 115, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 121, + 121, 122, 122, 123, 123, 124, 124, 125, + 125, 126, 126, 127, 127, 127, 128, 128, + 129, 129, 130, 130, 131, 131, 132, 132, + 133, 133, 134, 134, 135, 135, 136, 136, + 137, 137, 138, 138, 138, 139, 139, 140, + 140, 141, 141, 141, 142, 142, 143, 143, + 143, 144, 144, 145, 145, 145, 146, 146, + 146, 147, 147, 147, 148, 148, 149, 149, + 149, 150, 150, 150, 151, 151, 151, 152, + 152, 153, 153, 153, 154, 154, 155, 155, + 155, 156, 156, 157, 157, 157, 158, 158, + 159, 159, 159, 160, 160, 161, 161, 162, + 162, 162, 163, 163, 164, 164, 164, 165, + 165, 166, 166, 167, 167, 167, 168, 168, + 169, 169, 170, 170, 170, 171, 171, 172, + 172, 173, 173, 174, 174, 175, 175, 176, + 176, 177, 177, 178, 178, 179, 179, 180, + 180, 181, 182, 182, 183, 184, 184, 185, + 186, 186, 187, 188, 188, 189, 190, 191, + 191, 192, 193, 194, 195, 196, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 213, 214, + 215, 216, 218, 219, 220, 222, 223, 225, + 227, 228, 230, 232, 233, 235, 237, 239, + 241, 243, 245, 247, 249, 251, 253, 255 +}; +#elif (CONFIG_LCD == LCD_IPOD2BPP) || (CONFIG_LCD == LCD_IPODMINI) +/* measured and interpolated curve for mini LCD */ +/* TODO: verify this curve on the fullsize greyscale LCD */ +static const unsigned char lcdlinear[256] = { + 0, 3, 6, 8, 11, 14, 17, 19, + 22, 24, 27, 29, 32, 34, 36, 38, + 40, 42, 44, 45, 47, 48, 50, 51, + 52, 54, 55, 56, 57, 58, 58, 59, + 60, 61, 62, 62, 63, 64, 64, 65, + 66, 66, 67, 67, 68, 68, 69, 69, + 70, 70, 70, 71, 71, 71, 72, 72, + 73, 73, 73, 74, 74, 74, 74, 75, + 75, 75, 76, 76, 76, 77, 77, 77, + 78, 78, 78, 79, 79, 79, 80, 80, + 80, 80, 81, 81, 81, 82, 82, 82, + 83, 83, 83, 84, 84, 84, 85, 85, + 85, 85, 86, 86, 86, 87, 87, 87, + 87, 88, 88, 88, 89, 89, 89, 89, + 90, 90, 90, 91, 91, 91, 92, 92, + 92, 93, 93, 93, 94, 94, 94, 95, + 95, 96, 96, 96, 97, 97, 98, 98, + 99, 99, 99, 100, 100, 101, 101, 102, + 102, 103, 103, 104, 104, 105, 105, 106, + 106, 107, 107, 108, 108, 109, 109, 110, + 110, 111, 111, 112, 113, 113, 114, 114, + 115, 115, 116, 117, 117, 118, 118, 119, + 120, 120, 121, 122, 122, 123, 124, 124, + 125, 126, 126, 127, 128, 128, 129, 130, + 131, 131, 132, 133, 134, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 152, 153, + 154, 156, 157, 159, 160, 162, 163, 165, + 167, 168, 170, 172, 174, 176, 178, 180, + 182, 184, 187, 189, 192, 194, 197, 200, + 203, 206, 209, 212, 215, 219, 222, 226, + 229, 233, 236, 240, 244, 248, 251, 255 +}; +#endif +#else /* SIMULATOR */ +/* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */ +static const unsigned char lcdlinear[256] = { + 0, 16, 23, 28, 32, 36, 39, 42, + 45, 48, 50, 53, 55, 58, 60, 62, + 64, 66, 68, 70, 71, 73, 75, 77, + 78, 80, 81, 83, 84, 86, 87, 89, + 90, 92, 93, 94, 96, 97, 98, 100, + 101, 102, 103, 105, 106, 107, 108, 109, + 111, 112, 113, 114, 115, 116, 117, 118, + 119, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 145, 146, 147, 148, 149, + 150, 151, 151, 152, 153, 154, 155, 156, + 156, 157, 158, 159, 160, 160, 161, 162, + 163, 164, 164, 165, 166, 167, 167, 168, + 169, 170, 170, 171, 172, 173, 173, 174, + 175, 176, 176, 177, 178, 179, 179, 180, + 181, 181, 182, 183, 183, 184, 185, 186, + 186, 187, 188, 188, 189, 190, 190, 191, + 192, 192, 193, 194, 194, 195, 196, 196, + 197, 198, 198, 199, 199, 200, 201, 201, + 202, 203, 203, 204, 204, 205, 206, 206, + 207, 208, 208, 209, 209, 210, 211, 211, + 212, 212, 213, 214, 214, 215, 215, 216, + 217, 217, 218, 218, 219, 220, 220, 221, + 221, 222, 222, 223, 224, 224, 225, 225, + 226, 226, 227, 228, 228, 229, 229, 230, + 230, 231, 231, 232, 233, 233, 234, 234, + 235, 235, 236, 236, 237, 237, 238, 238, + 239, 240, 240, 241, 241, 242, 242, 243, + 243, 244, 244, 245, 245, 246, 246, 247, + 247, 248, 248, 249, 249, 250, 250, 251, + 251, 252, 252, 253, 253, 254, 254, 255 +}; +#endif /* SIMULATOR */ + +/* Prototypes */ +static inline void _deferred_update(void) __attribute__ ((always_inline)); +static int exp_s16p16(int x); +static int log_s16p16(int x); +static void grey_screendump_hook(int fd); +#ifdef SIMULATOR +static unsigned long _grey_get_pixel(int x, int y); +#else +static void _timer_isr(void); +#endif + +/* Update LCD areas not covered by the greyscale overlay */ +static inline void _deferred_update(void) +{ + int x1 = MAX(_grey_info.x, 0); + int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH); + int y1 = MAX(_grey_info.y, 0); + int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT); + + if (y1 > 0) /* refresh part above overlay, full width */ + _grey_rb->lcd_update_rect(0, 0, LCD_WIDTH, y1); + + if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */ + _grey_rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2); + + if (x1 > 0) /* refresh part to the left of overlay */ + _grey_rb->lcd_update_rect(0, y1, x1, y2 - y1); + + if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */ + _grey_rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1); +} + +#ifndef SIMULATOR +/* Timer interrupt handler: display next frame */ +static void _timer_isr(void) +{ +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.bx, _grey_info.y, + _grey_info.bwidth, _grey_info.height, + _grey_info.width); +#else + _grey_rb->lcd_grey_phase_blit(_grey_info.data, _grey_info.x, _grey_info.by, + _grey_info.width, _grey_info.bheight, + _grey_info.width); +#endif + + if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */ + { + _deferred_update(); + _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */ + } +} +#endif /* !SIMULATOR */ + +/* fixed point exp() */ +static int exp_s16p16(int x) +{ + int t; + int y = 0x00010000; + + if (x < 0) x += 0xb1721, y >>= 16; + t = x - 0x58b91; if (t >= 0) x = t, y <<= 8; + t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4; + t = x - 0x162e4; if (t >= 0) x = t, y <<= 2; + t = x - 0x0b172; if (t >= 0) x = t, y <<= 1; + t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1; + t = x - 0x03920; if (t >= 0) x = t, y += y >> 2; + t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3; + t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4; + t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5; + t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6; + t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7; + y += ((y >> 8) * x) >> 8; + + return y; +} + +/* fixed point log() */ +static int log_s16p16(int x) +{ + int t; + int y = 0xa65af; + + if (x < 0x00008000) x <<=16, y -= 0xb1721; + if (x < 0x00800000) x <<= 8, y -= 0x58b91; + if (x < 0x08000000) x <<= 4, y -= 0x2c5c8; + if (x < 0x20000000) x <<= 2, y -= 0x162e4; + if (x < 0x40000000) x <<= 1, y -= 0x0b172; + t = x + (x >> 1); if ((t & 0x80000000) == 0) x = t, y -= 0x067cd; + t = x + (x >> 2); if ((t & 0x80000000) == 0) x = t, y -= 0x03920; + t = x + (x >> 3); if ((t & 0x80000000) == 0) x = t, y -= 0x01e27; + t = x + (x >> 4); if ((t & 0x80000000) == 0) x = t, y -= 0x00f85; + t = x + (x >> 5); if ((t & 0x80000000) == 0) x = t, y -= 0x007e1; + t = x + (x >> 6); if ((t & 0x80000000) == 0) x = t, y -= 0x003f8; + t = x + (x >> 7); if ((t & 0x80000000) == 0) x = t, y -= 0x001fe; + x = 0x80000000 - x; + y -= x >> 15; + + return y; +} + +/* Initialise the framework and prepare the greyscale display buffer + + arguments: + newrb = pointer to plugin api + gbuf = pointer to the memory area to use (e.g. plugin buffer) + gbuf_size = max usable size of the buffer + buffered = use chunky pixel buffering? + This allows to use all drawing functions, but needs more + memory. Unbuffered operation provides only a subset of + drawing functions. (only grey_bitmap drawing and scrolling) + width = width in pixels (1..LCD_WIDTH) + height = height in pixels (1..LCD_HEIGHT) + Note that depending on the target LCD, either height or + width are rounded up to a multiple of 4 or 8. + + result: + true on success, false on failure + + If you need info about the memory taken by the greyscale buffer, supply a + long* as the last parameter. This long will then contain the number of bytes + used. The total memory needed can be calculated as follows: + total_mem = + width * height * 2 [grey display data] + + buffered ? (width * height) : 0 [chunky buffer] + + 0..3 [alignment] + + The function is authentic regarding memory usage on the simulator, even + if it doesn't use all of the allocated memory. */ +bool grey_init(struct plugin_api* newrb, unsigned char *gbuf, long gbuf_size, + bool buffered, int width, int height, long *buf_taken) +{ + int bdim, i; + long plane_size, buftaken; + unsigned data; +#ifndef SIMULATOR + struct grey_data *grey_data, *grey_end; +#endif + + _grey_rb = newrb; + + if ((unsigned) width > LCD_WIDTH + || (unsigned) height > LCD_HEIGHT) + return false; + +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + bdim = (width + 7) >> 3; + width = bdim << 3; +#else /* vertical packing */ +#if LCD_DEPTH == 1 + bdim = (height + 7) >> 3; + height = bdim << 3; +#elif LCD_DEPTH == 2 + bdim = (height + 3) >> 2; + height = bdim << 2; +#endif +#endif + + /* the buffer has to be long aligned */ + buftaken = (-(long)gbuf) & 3; + gbuf += buftaken; + + plane_size = _GREY_MULUQ(width, height); + + if (buffered) /* chunky buffer */ + { + buftaken += plane_size; + _grey_info.buffer = gbuf; + gbuf += plane_size; + } + buftaken += sizeof(struct grey_data) * plane_size; + if (buftaken > gbuf_size) + return false; + +#ifdef SIMULATOR + _grey_info.buffer = gbuf; +#else + grey_data = (struct grey_data *)gbuf; + grey_end = grey_data + plane_size; + _grey_info.data = grey_data; + + while (grey_data < grey_end) + { + grey_data->phase = _grey_rb->rand() & 0xff; + grey_data->value = 128; /* init to white */ + grey_data++; + } +#endif + + _grey_info.x = 0; + _grey_info.y = 0; + _grey_info.width = width; + _grey_info.height = height; +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + _grey_info.bx = 0; + _grey_info.bwidth = bdim; +#else + _grey_info.by = 0; + _grey_info.bheight = bdim; +#endif + _grey_info.flags = 0; + _grey_info.fg_val = 0; + _grey_info.bg_val = 128; + _grey_info.fg_brightness = 0; + _grey_info.bg_brightness = 255; + _grey_info.drawmode = DRMODE_SOLID; + _grey_info.curfont = FONT_SYSFIXED; + + + /* precalculate the value -> pattern index conversion table, taking + linearisation and gamma correction into account */ + for (i = 0; i < 256; i++) + { + data = exp_s16p16(((2<<8) * log_s16p16(i * 257 + 1)) >> 8) + 128; + data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */ + data = (lcdlinear[data] << 7) + 127; + _grey_info.gvalue[i] = (data + (data >> 8)) >> 8; + /* approx. data / 255 */ + } + + if (buf_taken) /* caller requested info about space taken */ + *buf_taken = buftaken; + + return true; +} + +/* Release the greyscale display buffer and the library + DO CALL either this function or at least grey_show_display(false) + before you exit, otherwise nasty things may happen. */ +void grey_release(void) +{ + grey_show(false); +} + +/* Switch the greyscale overlay on or off + DO NOT call lcd_update() or any other api function that directly accesses + the lcd while the greyscale overlay is running! If you need to do + lcd_update() to update something outside the greyscale overlay area, use + grey_deferred_update() instead. + + Other functions to avoid are: + lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(), + lcd_set_invert_display(), lcd_set_flip() */ +void grey_show(bool enable) +{ + if (enable && !(_grey_info.flags & _GREY_RUNNING)) + { + _grey_info.flags |= _GREY_RUNNING; +#ifdef SIMULATOR + _grey_rb->sim_lcd_ex_init(129, _grey_get_pixel); + grey_update(); +#else /* !SIMULATOR */ +#ifdef NEED_BOOST + _grey_rb->cpu_boost(true); +#endif +#if CONFIG_LCD == LCD_SSD1815 + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 67, 1, _timer_isr); +#elif CONFIG_LCD == LCD_S1D15E06 + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 70, 1, _timer_isr); +#elif CONFIG_LCD == LCD_IPOD2BPP +#ifdef IPOD_1G2G + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 95, 1, _timer_isr); /* verified */ +#elif defined IPOD_3G + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 87, 1, _timer_isr); /* verified */ +#else + /* FIXME: verify value */ + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 80, 1, _timer_isr); +#endif +#elif CONFIG_LCD == LCD_IPODMINI + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 88, 1, _timer_isr); +#elif CONFIG_LCD == LCD_IFP7XX + _grey_rb->timer_register(1, NULL, TIMER_FREQ / 83, 1, _timer_isr); +#endif /* CONFIG_LCD */ +#endif /* !SIMULATOR */ + _grey_rb->screen_dump_set_hook(grey_screendump_hook); + } + else if (!enable && (_grey_info.flags & _GREY_RUNNING)) + { +#ifdef SIMULATOR + _grey_rb->sim_lcd_ex_init(0, NULL); +#else + _grey_rb->timer_unregister(); +#ifdef NEED_BOOST + _grey_rb->cpu_boost(false); +#endif +#endif + _grey_info.flags &= ~_GREY_RUNNING; + _grey_rb->screen_dump_set_hook(NULL); + _grey_rb->lcd_update(); /* restore whatever there was before */ + } +} + +#ifdef SIMULATOR +/* Callback function for grey_update_rect() to read a pixel from the greybuffer. + Note that x and y are in LCD coordinates, not greybuffer coordinates! */ +static unsigned long _grey_get_pixel(int x, int y) +{ + return _grey_info.buffer[(y - _grey_info.y) * _grey_info.width + + x - _grey_info.x] + (1 << LCD_DEPTH); +} + +/* Update a rectangular area of the greyscale overlay */ +void grey_update_rect(int x, int y, int width, int height) +{ + if (x + width > _grey_info.width) + width = _grey_info.width - x; + if (y + height > _grey_info.height) + height = _grey_info.height - y; + + x += _grey_info.x; + y += _grey_info.y; + + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; + + _grey_rb->sim_lcd_ex_update_rect(x, y, width, height); +} + +#else /* !SIMULATOR */ + +void grey_update_rect(int x, int y, int width, int height) +{ + unsigned char *src; + + if ((width <= 0) || (height <= 0)) + return; /* nothing to do */ + + if (y + height > _grey_info.height) + height = _grey_info.height - y; + if (x + width > _grey_info.width) + width = _grey_info.width - x; + + src = _grey_info.buffer + _GREY_MULUQ(_grey_info.width, y) + x; + + do + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + int idx = _GREY_MULUQ(_grey_info.width, y) + x; +#else +#if LCD_DEPTH == 1 + int idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (x << 3) + (~y & 7); +#elif LCD_DEPTH == 2 + int idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (x << 2) + (~y & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + unsigned char *dst_row = &_grey_info.data[idx].value; + unsigned char *src_row = src; + unsigned char *src_end = src + width; + + do + { + *dst_row = *src_row++; + dst_row += _GREY_X_ADVANCE; + } + while (src_row < src_end); + + y++; + src += _grey_info.width; + } + while (--height > 0); +} + +#endif /* !SIMULATOR */ + +/* Update the whole greyscale overlay */ +void grey_update(void) +{ + grey_update_rect(0, 0, _grey_info.width, _grey_info.height); +} + +/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions + (in areas of the screen not covered by the greyscale overlay). */ +void grey_deferred_lcd_update(void) +{ + if (_grey_info.flags & _GREY_RUNNING) + { +#ifdef SIMULATOR + _deferred_update(); +#else + _grey_info.flags |= _GREY_DEFERRED_UPDATE; +#endif + } + else + _grey_rb->lcd_update(); +} + +/*** Screenshot ***/ + +#define BMP_FIXEDCOLORS (1 << LCD_DEPTH) +#define BMP_VARCOLORS 129 +#define BMP_NUMCOLORS (BMP_FIXEDCOLORS + BMP_VARCOLORS) +#define BMP_BPP 8 +#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3) +#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS) +#define BMP_DATASIZE (BMP_LINESIZE * LCD_HEIGHT) +#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE) + +#define LE16_CONST(x) (x)&0xff, ((x)>>8)&0xff +#define LE32_CONST(x) (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff + +static const unsigned char bmpheader[] = +{ + 0x42, 0x4d, /* 'BM' */ + LE32_CONST(BMP_TOTALSIZE), /* Total file size */ + 0x00, 0x00, 0x00, 0x00, /* Reserved */ + LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */ + + 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */ + LE32_CONST(LCD_WIDTH), /* Width in pixels */ + LE32_CONST(LCD_HEIGHT), /* Height in pixels */ + 0x01, 0x00, /* Number of planes (always 1) */ + LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */ + 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */ + LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */ + 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */ + 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */ + LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */ + LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */ + + /* Fixed colours */ +#if LCD_DEPTH == 1 + 0x90, 0xee, 0x90, 0x00, /* Colour #0 */ + 0x00, 0x00, 0x00, 0x00 /* Colour #1 */ +#elif LCD_DEPTH == 2 + 0xe6, 0xd8, 0xad, 0x00, /* Colour #0 */ + 0x99, 0x90, 0x73, 0x00, /* Colour #1 */ + 0x4c, 0x48, 0x39, 0x00, /* Colour #2 */ + 0x00, 0x00, 0x00, 0x00 /* Colour #3 */ +#endif +}; + +#if LCD_DEPTH == 1 +#define BMP_RED 0x90 +#define BMP_GREEN 0xee +#define BMP_BLUE 0x90 +#elif LCD_DEPTH == 2 +#define BMP_RED 0xad +#define BMP_GREEN 0xd8 +#define BMP_BLUE 0xe6 +#endif + +/* Hook function for core screen_dump() to save the current display + content (b&w and greyscale overlay) to an 8-bit BMP file. */ +static void grey_screendump_hook(int fd) +{ + int i; + int x, y, gx, gy; +#if LCD_PIXELFORMAT == VERTICAL_PACKING +#if LCD_DEPTH == 1 + unsigned mask; +#elif LCD_DEPTH == 2 + int shift; +#endif +#endif /* LCD_PIXELFORMAT == VERTICAL_PACKING */ + unsigned char *lcdptr; + unsigned char *clut_entry; + unsigned char linebuf[MAX(4*BMP_VARCOLORS,BMP_LINESIZE)]; + + _grey_rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */ + + /* build clut */ + _grey_rb->memset(linebuf, 0, 4*BMP_VARCOLORS); + clut_entry = linebuf; + + for (i = 0; i <= 128; i++) + { + *clut_entry++ = _GREY_MULUQ(BMP_BLUE, i) >> 7; + *clut_entry++ = _GREY_MULUQ(BMP_GREEN, i) >> 7; + *clut_entry++ = _GREY_MULUQ(BMP_RED, i) >> 7; + clut_entry++; + } + _grey_rb->write(fd, linebuf, 4*BMP_VARCOLORS); + + /* BMP image goes bottom -> top */ + for (y = LCD_HEIGHT - 1; y >= 0; y--) + { + _grey_rb->memset(linebuf, 0, BMP_LINESIZE); + + gy = y - _grey_info.y; +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING +#if LCD_DEPTH == 2 + lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_FBWIDTH, y); + + for (x = 0; x < LCD_WIDTH; x += 4) + { + gx = x - _grey_info.x; + + if (((unsigned)gy < (unsigned)_grey_info.height) + && ((unsigned)gx < (unsigned)_grey_info.width)) + { +#ifdef SIMULATOR + unsigned char *src = _grey_info.buffer + + _GREY_MULUQ(_grey_info.width, gy) + gx; + + for (i = 0; i < 4; i++) + linebuf[x + i] = BMP_FIXEDCOLORS + *src++; +#else + unsigned char *src = &_grey_info.data[_GREY_MULUQ(_grey_info.width, + gy) + gx].value; + for (i = 0; i < 4; i++) + { + linebuf[x + i] = BMP_FIXEDCOLORS + *src; + src += _GREY_X_ADVANCE; + } +#endif + } + else + { + unsigned data = *lcdptr; + linebuf[x] = (data >> 6) & 3; + linebuf[x + 1] = (data >> 4) & 3; + linebuf[x + 2] = (data >> 2) & 3; + linebuf[x + 3] = data & 3; + } + lcdptr++; + } +#endif /* LCD_DEPTH */ +#else /* LCD_PIXELFORMAT == VERTICAL_PACKING */ +#if LCD_DEPTH == 1 + mask = 1 << (y & 7); + lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 3); + + for (x = 0; x < LCD_WIDTH; x++) + { + gx = x - _grey_info.x; + + if (((unsigned)gy < (unsigned)_grey_info.height) + && ((unsigned)gx < (unsigned)_grey_info.width)) + { +#ifdef SIMULATOR + linebuf[x] = BMP_FIXEDCOLORS + + _grey_info.buffer[_GREY_MULUQ(_grey_info.width, + gy) + gx]; +#else + linebuf[x] = BMP_FIXEDCOLORS + + _grey_info.data[_GREY_MULUQ(_grey_info.width, + gy & ~7) + (gx << 3) + (~gy & 7)].value; +#endif + } + else + { + linebuf[x] = (*lcdptr & mask) ? 1 : 0; + } + lcdptr++; + } +#elif LCD_DEPTH == 2 + shift = 2 * (y & 3); + lcdptr = _grey_rb->lcd_framebuffer + _GREY_MULUQ(LCD_WIDTH, y >> 2); + + for (x = 0; x < LCD_WIDTH; x++) + { + gx = x - _grey_info.x; + + if (((unsigned)gy < (unsigned)_grey_info.height) + && ((unsigned)gx < (unsigned)_grey_info.width)) + { +#ifdef SIMULATOR + linebuf[x] = BMP_FIXEDCOLORS + + _grey_info.buffer[_GREY_MULUQ(_grey_info.width, + gy) + gx]; +#else + linebuf[x] = BMP_FIXEDCOLORS + + _grey_info.data[_GREY_MULUQ(_grey_info.width, + gy & ~3) + (gx << 2) + (~gy & 7)].value; +#endif + } + else + { + linebuf[x] = (*lcdptr >> shift) & 3; + } + lcdptr++; + } +#endif /* LCD_DEPTH */ +#endif /* LCD_PIXELFORMAT */ + + _grey_rb->write(fd, linebuf, BMP_LINESIZE); + } +} diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c new file mode 100644 index 0000000..e243b5f --- /dev/null +++ b/apps/plugins/lib/grey_draw.c @@ -0,0 +1,681 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* New greyscale framework +* Drawing functions +* +* This is a generic framework to display 129 shades of grey on low-depth +* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins. +* +* Copyright (C) 2008 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include "plugin.h" +#include "grey.h" + +/*** low-level drawing functions ***/ + +static void setpixel(unsigned char *address) +{ + *address = _grey_info.fg_val; +} + +static void clearpixel(unsigned char *address) +{ + *address = _grey_info.bg_val; +} + +static void flippixel(unsigned char *address) +{ + *address = 128 - *address; +} + +static void nopixel(unsigned char *address) +{ + (void)address; +} + +void (* const _grey_pixelfuncs[8])(unsigned char *address) = { + flippixel, nopixel, setpixel, setpixel, + nopixel, clearpixel, nopixel, clearpixel +}; + +/*** Drawing functions ***/ + +/* Clear the whole display */ +void grey_clear_display(void) +{ + int value = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + _grey_rb->memset(_grey_info.buffer, value, + _GREY_MULUQ(_grey_info.width, _grey_info.height)); +} + +/* Set a single pixel */ +void grey_drawpixel(int x, int y) +{ + if (((unsigned)x < (unsigned)_grey_info.width) + && ((unsigned)y < (unsigned)_grey_info.height)) + _grey_pixelfuncs[_grey_info.drawmode](&_grey_info.buffer[_GREY_MULUQ( + _grey_info.width, y) + x]); +} + +/* Draw a line */ +void grey_drawline(int x1, int y1, int x2, int y2) +{ + int numpixels; + int i; + int deltax, deltay; + int d, dinc1, dinc2; + int x, xinc1, xinc2; + int y, yinc1, yinc2; + void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[_grey_info.drawmode]; + + deltax = abs(x2 - x1); + deltay = abs(y2 - y1); + xinc2 = 1; + yinc2 = 1; + + if (deltax >= deltay) + { + numpixels = deltax; + d = 2 * deltay - deltax; + dinc1 = deltay * 2; + dinc2 = (deltay - deltax) * 2; + xinc1 = 1; + yinc1 = 0; + } + else + { + numpixels = deltay; + d = 2 * deltax - deltay; + dinc1 = deltax * 2; + dinc2 = (deltax - deltay) * 2; + xinc1 = 0; + yinc1 = 1; + } + numpixels++; /* include endpoints */ + + if (x1 > x2) + { + xinc1 = -xinc1; + xinc2 = -xinc2; + } + + if (y1 > y2) + { + yinc1 = -yinc1; + yinc2 = -yinc2; + } + + x = x1; + y = y1; + + for (i = 0; i < numpixels; i++) + { + if (((unsigned)x < (unsigned)_grey_info.width) + && ((unsigned)y < (unsigned)_grey_info.height)) + pfunc(&_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]); + + if (d < 0) + { + d += dinc1; + x += xinc1; + y += yinc1; + } + else + { + d += dinc2; + x += xinc2; + y += yinc2; + } + } +} + +/* Draw a horizontal line (optimised) */ +void grey_hline(int x1, int x2, int y) +{ + int x; + int value = 0; + unsigned char *dst; + bool fillopt = false; + void (*pfunc)(unsigned char *address); + + /* direction flip */ + if (x2 < x1) + { + x = x1; + x1 = x2; + x2 = x; + } + + /* nothing to draw? */ + if (((unsigned)y >= (unsigned)_grey_info.height) + || (x1 >= _grey_info.width) || (x2 < 0)) + return; + + /* clipping */ + if (x1 < 0) + x1 = 0; + if (x2 >= _grey_info.width) + x2 = _grey_info.width - 1; + + if (_grey_info.drawmode & DRMODE_INVERSEVID) + { + if (_grey_info.drawmode & DRMODE_BG) + { + fillopt = true; + value = _grey_info.bg_val; + } + } + else + { + if (_grey_info.drawmode & DRMODE_FG) + { + fillopt = true; + value = _grey_info.fg_val; + } + } + pfunc = _grey_pixelfuncs[_grey_info.drawmode]; + dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x1]; + + if (fillopt) + _grey_rb->memset(dst, value, x2 - x1 + 1); + else + { + unsigned char *dst_end = dst + x2 - x1; + do + pfunc(dst++); + while (dst <= dst_end); + } +} + +/* Draw a vertical line (optimised) */ +void grey_vline(int x, int y1, int y2) +{ + int y; + unsigned char *dst, *dst_end; + void (*pfunc)(unsigned char *address); + + /* direction flip */ + if (y2 < y1) + { + y = y1; + y1 = y2; + y2 = y; + } + + /* nothing to draw? */ + if (((unsigned)x >= (unsigned)_grey_info.width) + || (y1 >= _grey_info.height) || (y2 < 0)) + return; + + /* clipping */ + if (y1 < 0) + y1 = 0; + if (y2 >= _grey_info.height) + y2 = _grey_info.height - 1; + + pfunc = _grey_pixelfuncs[_grey_info.drawmode]; + dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y1) + x]; + + dst_end = dst + _GREY_MULUQ(_grey_info.width, y2 - y1); + do + { + pfunc(dst); + dst += _grey_info.width; + } + while (dst <= dst_end); +} + +/* Draw a filled triangle */ +void grey_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3) +{ + int x, y; + long fp_x1, fp_x2, fp_dx1, fp_dx2; + + /* sort vertices by increasing y value */ + if (y1 > y3) + { + if (y2 < y3) /* y2 < y3 < y1 */ + { + x = x1; x1 = x2; x2 = x3; x3 = x; + y = y1; y1 = y2; y2 = y3; y3 = y; + } + else if (y2 > y1) /* y3 < y1 < y2 */ + { + x = x1; x1 = x3; x3 = x2; x2 = x; + y = y1; y1 = y3; y3 = y2; y2 = y; + } + else /* y3 <= y2 <= y1 */ + { + x = x1; x1 = x3; x3 = x; + y = y1; y1 = y3; y3 = y; + } + } + else + { + if (y2 < y1) /* y2 < y1 <= y3 */ + { + x = x1; x1 = x2; x2 = x; + y = y1; y1 = y2; y2 = y; + } + else if (y2 > y3) /* y1 <= y3 < y2 */ + { + x = x2; x2 = x3; x3 = x; + y = y2; y2 = y3; y3 = y; + } + /* else already sorted */ + } + + if (y1 < y3) /* draw */ + { + fp_dx1 = ((x3 - x1) << 16) / (y3 - y1); + fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1); + + if (y1 < y2) /* first part */ + { + fp_dx2 = ((x2 - x1) << 16) / (y2 - y1); + fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1); + for (y = y1; y < y2; y++) + { + grey_hline(fp_x1 >> 16, fp_x2 >> 16, y); + fp_x1 += fp_dx1; + fp_x2 += fp_dx2; + } + } + if (y2 < y3) /* second part */ + { + fp_dx2 = ((x3 - x2) << 16) / (y3 - y2); + fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1); + for (y = y2; y < y3; y++) + { + grey_hline(fp_x1 >> 16, fp_x2 >> 16, y); + fp_x1 += fp_dx1; + fp_x2 += fp_dx2; + } + } + } +} + +/* Draw a rectangular box */ +void grey_drawrect(int x, int y, int width, int height) +{ + if ((width <= 0) || (height <= 0)) + return; + + int x2 = x + width - 1; + int y2 = y + height - 1; + + grey_vline(x, y, y2); + grey_vline(x2, y, y2); + grey_hline(x, x2, y); + grey_hline(x, x2, y2); +} + +/* Fill a rectangular area */ +void grey_fillrect(int x, int y, int width, int height) +{ + int value = 0; + unsigned char *dst, *dst_end; + bool fillopt = false; + void (*pfunc)(unsigned char *address); + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) + || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > _grey_info.width) + width = _grey_info.width - x; + if (y + height > _grey_info.height) + height = _grey_info.height - y; + + if (_grey_info.drawmode & DRMODE_INVERSEVID) + { + if (_grey_info.drawmode & DRMODE_BG) + { + fillopt = true; + value = _grey_info.bg_val; + } + } + else + { + if (_grey_info.drawmode & DRMODE_FG) + { + fillopt = true; + value = _grey_info.fg_val; + } + } + pfunc = _grey_pixelfuncs[_grey_info.drawmode]; + dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]; + dst_end = dst + _GREY_MULUQ(_grey_info.width, height); + + do + { + if (fillopt) + _grey_rb->memset(dst, value, width); + else + { + unsigned char *dst_row = dst; + unsigned char *row_end = dst_row + width; + + do + pfunc(dst_row++); + while (dst_row < row_end); + } + dst += _grey_info.width; + } + while (dst < dst_end); +} + +/* About Rockbox' internal monochrome bitmap format: + * + * A bitmap contains one bit for every pixel that defines if that pixel is + * foreground (1) or background (0). Bits within a byte are arranged + * vertically, LSB at top. + * The bytes are stored in row-major order, with byte 0 being top left, + * byte 1 2nd from left etc. The first row of bytes defines pixel rows + * 0..7, the second row defines pixel row 8..15 etc. */ + +/* Draw a partial monochrome bitmap */ +void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + const unsigned char *src_end; + unsigned char *dst, *dst_end; + void (*fgfunc)(unsigned char *address); + void (*bgfunc)(unsigned char *address); + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) + || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > _grey_info.width) + width = _grey_info.width - x; + if (y + height > _grey_info.height) + height = _grey_info.height - y; + + src += _GREY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */ + src_y &= 7; + src_end = src + width; + + fgfunc = _grey_pixelfuncs[_grey_info.drawmode]; + bgfunc = _grey_pixelfuncs[_grey_info.drawmode ^ DRMODE_INVERSEVID]; + dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]; + + do + { + const unsigned char *src_col = src++; + unsigned char *dst_col = dst++; + unsigned data = *src_col >> src_y; + int numbits = 8 - src_y; + + dst_end = dst_col + _GREY_MULUQ(_grey_info.width, height); + do + { + if (data & 0x01) + fgfunc(dst_col); + else + bgfunc(dst_col); + + dst_col += _grey_info.width; + + data >>= 1; + if (--numbits == 0) + { + src_col += stride; + data = *src_col; + numbits = 8; + } + } + while (dst_col < dst_end); + } + while (src < src_end); +} + +/* Draw a full monochrome bitmap */ +void grey_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) +{ + grey_mono_bitmap_part(src, 0, 0, width, x, y, width, height); +} + +/* Draw a partial greyscale bitmap, canonical format */ +void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + unsigned char *dst, *dst_end; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) + || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > _grey_info.width) + width = _grey_info.width - x; + if (y + height > _grey_info.height) + height = _grey_info.height - y; + + src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */ + dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]; + dst_end = dst + _GREY_MULUQ(_grey_info.width, height); + + do + { + const unsigned char *src_row = src; + unsigned char *dst_row = dst; + unsigned char *row_end = dst_row + width; + + do + *dst_row++ = _grey_info.gvalue[*src_row++]; + while (dst_row < row_end); + + src += stride; + dst += _grey_info.width; + } + while (dst < dst_end); +} + +/* Draw a full greyscale bitmap, canonical format */ +void grey_gray_bitmap(const unsigned char *src, int x, int y, int width, + int height) +{ + grey_gray_bitmap_part(src, 0, 0, width, x, y, width, height); +} + +/* Put a string at a given pixel position, skipping first ofs pixel columns */ +void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str) +{ + int ch; + struct font* pf = _grey_rb->font_get(_grey_info.curfont); + + while ((ch = *str++) != '\0' && x < _grey_info.width) + { + int width; + const unsigned char *bits; + + /* check input range */ + if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) + ch = pf->defaultchar; + ch -= pf->firstchar; + + /* get proportional width and glyph bits */ + width = pf->width ? pf->width[ch] : pf->maxwidth; + + if (ofs > width) + { + ofs -= width; + continue; + } + + bits = pf->bits + (pf->offset ? + pf->offset[ch] : (((pf->height + 7) >> 3) * pf->maxwidth * ch)); + + grey_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); + + x += width - ofs; + ofs = 0; + } +} + +/* Put a string at a given pixel position */ +void grey_putsxy(int x, int y, const unsigned char *str) +{ + grey_putsxyofs(x, y, 0, str); +} + +/*** Unbuffered drawing functions ***/ + +#ifdef SIMULATOR + +/* Clear the whole display */ +void grey_ub_clear_display(void) +{ + grey_clear_display(); + grey_update(); +} + +/* Draw a partial greyscale bitmap, canonical format */ +void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + grey_gray_bitmap_part(src, src_x, src_y, stride, x, y, width, height); + grey_update_rect(x, y, width, height); +} + +#else /* !SIMULATOR */ + +/* Clear the greyscale display (sets all pixels to white) */ +void grey_ub_clear_display(void) +{ + int value = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + unsigned char *dst = &_grey_info.data[0].value; + unsigned char *dst_end = dst + sizeof(struct grey_data) + * _GREY_MULUQ(_grey_info.width, _grey_info.height); + + do + { + *dst = value; + dst += sizeof(struct grey_data); + } + while (dst < dst_end); +} + +/* Draw a partial greyscale bitmap, canonical format */ +void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) + || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > _grey_info.width) + width = _grey_info.width - x; + if (y + height > _grey_info.height) + height = _grey_info.height - y; + + src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */ + + do + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + int idx = _GREY_MULUQ(_grey_info.width, y) + x; +#else +#if LCD_DEPTH == 1 + int idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (x << 3) + (~y & 7); +#elif LCD_DEPTH == 2 + int idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (x << 2) + (~y & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + unsigned char *dst_row = &_grey_info.data[idx].value; + const unsigned char *src_row = src; + const unsigned char *src_end = src + width; + + do + { + *dst_row = _grey_info.gvalue[*src_row++]; + dst_row += _GREY_X_ADVANCE; + } + while (src_row < src_end); + + y++; + src += stride; + } + while (--height > 0); +} + +#endif /* !SIMULATOR */ + +/* Draw a full greyscale bitmap, canonical format */ +void grey_ub_gray_bitmap(const unsigned char *src, int x, int y, int width, + int height) +{ + grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height); +} diff --git a/apps/plugins/lib/grey_parm.c b/apps/plugins/lib/grey_parm.c new file mode 100644 index 0000000..6d60505 --- /dev/null +++ b/apps/plugins/lib/grey_parm.c @@ -0,0 +1,116 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* New greyscale framework +* Parameter handling +* +* This is a generic framework to display 129 shades of grey on low-depth +* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins. +* +* Copyright (C) 2008 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include "plugin.h" +#include "grey.h" + +/* Set position of the top left corner of the greyscale overlay + Note that depending on the target LCD, either x or y gets rounded + to the nearest multiple of 4 or 8 */ +void grey_set_position(int x, int y) +{ +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + _grey_info.bx = (x + 4) >> 3; + x = 8 * _grey_info.bx; +#else +#if LCD_DEPTH == 1 + _grey_info.by = (y + 4) >> 3; + y = 8 * _grey_info.by; +#elif LCD_DEPTH == 2 + _grey_info.by = (y + 2) >> 2; + y = 4 * _grey_info.by; +#endif +#endif /* LCD_PIXELFORMAT */ + _grey_info.x = x; + _grey_info.y = y; + + if (_grey_info.flags & _GREY_RUNNING) + { +#ifdef SIMULATOR + grey_deferred_lcd_update(); + grey_update(); +#else + _grey_info.flags |= _GREY_DEFERRED_UPDATE; +#endif + } +} + +/* Set the draw mode for subsequent drawing operations */ +void grey_set_drawmode(int mode) +{ + _grey_info.drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); +} + +/* Return the current draw mode */ +int grey_get_drawmode(void) +{ + return _grey_info.drawmode; +} + +/* Set the foreground shade for subsequent drawing operations */ +void grey_set_foreground(unsigned brightness) +{ + _grey_info.fg_val = _grey_info.gvalue[brightness]; + _grey_info.fg_brightness = brightness; +} + +/* Return the current foreground shade */ +unsigned grey_get_foreground(void) +{ + return _grey_info.fg_brightness; +} + +/* Set the background shade for subsequent drawing operations */ +void grey_set_background(unsigned brightness) +{ + _grey_info.bg_val = _grey_info.gvalue[brightness]; + _grey_info.bg_brightness = brightness; +} + +/* Return the current background shade */ +unsigned grey_get_background(void) +{ + return _grey_info.bg_brightness; +} + +/* Set draw mode, foreground and background shades at once */ +void grey_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) +{ + grey_set_drawmode(mode); + grey_set_foreground(fg_brightness); + grey_set_background(bg_brightness); +} + +/* Set font for the text output routines */ +void grey_setfont(int newfont) +{ + _grey_info.curfont = newfont; +} + +/* Get width and height of a text when printed with the current font */ +int grey_getstringsize(const unsigned char *str, int *w, int *h) +{ + return _grey_rb->font_getstringsize(str, w, h, _grey_info.curfont); +} diff --git a/apps/plugins/lib/grey_scroll.c b/apps/plugins/lib/grey_scroll.c new file mode 100644 index 0000000..80496e7 --- /dev/null +++ b/apps/plugins/lib/grey_scroll.c @@ -0,0 +1,358 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id$ +* +* New greyscale framework +* Scrolling routines +* +* This is a generic framework to display 129 shades of grey on low-depth +* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins. +* +* Copyright (C) 2008 Jens Arnold +* +* All files in this archive are subject to the GNU General Public License. +* See the file COPYING in the source tree root for full license agreement. +* +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +* KIND, either express or implied. +* +****************************************************************************/ + +#include "plugin.h" +#include "grey.h" + +/*** Scrolling ***/ + +/* Scroll left */ +void grey_scroll_left(int count) +{ + unsigned char *data, *data_end; + int length, blank; + + if ((unsigned)count >= (unsigned)_grey_info.width) + return; + + data = _grey_info.buffer; + data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); + length = _grey_info.width - count; + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + do + { + _grey_rb->memmove(data, data + count, length); + _grey_rb->memset(data + length, blank, count); + data += _grey_info.width; + } + while (data < data_end); +} + +/* Scroll right */ +void grey_scroll_right(int count) +{ + unsigned char *data, *data_end; + int length, blank; + + if ((unsigned)count >= (unsigned)_grey_info.width) + return; + + data = _grey_info.buffer; + data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); + length = _grey_info.width - count; + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + do + { + _grey_rb->memmove(data + count, data, length); + _grey_rb->memset(data, blank, count); + data += _grey_info.width; + } + while (data < data_end); +} + +/* Scroll up */ +void grey_scroll_up(int count) +{ + long shift, length; + int blank; + + if ((unsigned)count >= (unsigned)_grey_info.height) + return; + + shift = _GREY_MULUQ(_grey_info.width, count); + length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count); + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + _grey_rb->memmove(_grey_info.buffer, _grey_info.buffer + shift, length); + _grey_rb->memset(_grey_info.buffer + length, blank, shift); +} + +/* Scroll down */ +void grey_scroll_down(int count) +{ + long shift, length; + int blank; + + if ((unsigned)count >= (unsigned)_grey_info.height) + return; + + shift = _GREY_MULUQ(_grey_info.width, count); + length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count); + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + _grey_rb->memmove(_grey_info.buffer + shift, _grey_info.buffer, length); + _grey_rb->memset(_grey_info.buffer, blank, shift); +} + +/*** Unbuffered scrolling functions ***/ + +#ifdef SIMULATOR + +/* Scroll left */ +void grey_ub_scroll_left(int count) +{ + grey_scroll_left(count); + grey_update(); +} + +/* Scroll right */ +void grey_ub_scroll_right(int count) +{ + grey_scroll_right(count); + grey_update(); +} + +/* Scroll up */ +void grey_ub_scroll_up(int count) +{ + grey_scroll_up(count); + grey_update(); +} + +/* Scroll down */ +void grey_ub_scroll_down(int count) +{ + grey_scroll_down(count); + grey_update(); +} + +#else /* !SIMULATOR */ + +/* Scroll left */ +void grey_ub_scroll_left(int count) +{ + unsigned char *dst, *src, *end; + int blank, y, idx; + + if ((count == 0) || ((unsigned)count >= (unsigned)_grey_info.width)) + return; + + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + for (y = 0; y < _grey_info.height; y++) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + idx = _GREY_MULUQ(_grey_info.width, y); +#else +#if LCD_DEPTH == 1 + idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (~y & 7); +#elif LCD_DEPTH == 2 + idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (~y & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + dst = &_grey_info.data[idx].value; + src = dst + count * _GREY_X_ADVANCE; + end = dst + _grey_info.width * _GREY_X_ADVANCE; + + do + { + *dst = *src; + dst += _GREY_X_ADVANCE; + src += _GREY_X_ADVANCE; + } + while (src < end); + + do + { + *dst = blank; + dst += _GREY_X_ADVANCE; + } + while (dst < end); + } +} + +/* Scroll right */ +void grey_ub_scroll_right(int count) +{ + unsigned char *dst, *src, *start; + int blank, y, idx; + + if ((count == 0) || ((unsigned)count >= (unsigned)_grey_info.width)) + return; + + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + for (y = 0; y < _grey_info.height; y++) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + idx = _GREY_MULUQ(_grey_info.width, y); +#else +#if LCD_DEPTH == 1 + idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (~y & 7); +#elif LCD_DEPTH == 2 + idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (~y & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + start = &_grey_info.data[idx].value; + dst = start + _grey_info.width * _GREY_X_ADVANCE; + src = dst - count * _GREY_X_ADVANCE; + + do + { + dst -= _GREY_X_ADVANCE; + src -= _GREY_X_ADVANCE; + *dst = *src; + } + while (src > start); + + do + { + dst -= _GREY_X_ADVANCE; + *dst = blank; + } + while (dst > start); + } +} + +void grey_ub_scroll_up(int count) +{ + unsigned char *dst, *dst_end, *src; + int blank, ys, yd, is, id; + + if ((unsigned)count >= (unsigned)_grey_info.height) + return; + + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + for (ys = count, yd = 0; ys < _grey_info.height; ys++, yd++) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + id = _GREY_MULUQ(_grey_info.width, yd); + is = _GREY_MULUQ(_grey_info.width, ys); +#else +#if LCD_DEPTH == 1 + id = _GREY_MULUQ(_grey_info.width, yd & ~7) + (~yd & 7); + is = _GREY_MULUQ(_grey_info.width, ys & ~7) + (~ys & 7); +#elif LCD_DEPTH == 2 + id = _GREY_MULUQ(_grey_info.width, yd & ~3) + (~yd & 3); + is = _GREY_MULUQ(_grey_info.width, ys & ~3) + (~ys & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + dst = &_grey_info.data[id].value; + src = &_grey_info.data[is].value; + dst_end = dst + _grey_info.width * _GREY_X_ADVANCE; + + do + { + *dst = *src; + dst += _GREY_X_ADVANCE; + src += _GREY_X_ADVANCE; + } + while (dst < dst_end); + } + for (; yd < _grey_info.height; yd++) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + id = _GREY_MULUQ(_grey_info.width, yd); +#else +#if LCD_DEPTH == 1 + id = _GREY_MULUQ(_grey_info.width, yd & ~7) + (~yd & 7); +#elif LCD_DEPTH == 2 + id = _GREY_MULUQ(_grey_info.width, yd & ~3) + (~yd & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + dst = &_grey_info.data[id].value; + dst_end = dst + _grey_info.width * _GREY_X_ADVANCE; + + do + { + *dst = blank; + dst += _GREY_X_ADVANCE; + } + while (dst < dst_end); + } +} + +void grey_ub_scroll_down(int count) +{ + unsigned char *dst, *dst_end, *src; + int blank, ys, yd, is, id; + + if ((unsigned)count >= (unsigned)_grey_info.height) + return; + + blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? + _grey_info.fg_val : _grey_info.bg_val; + + yd = _grey_info.height - 1; + for (ys = yd - count; ys >= 0; ys--, yd--) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + id = _GREY_MULUQ(_grey_info.width, yd); + is = _GREY_MULUQ(_grey_info.width, ys); +#else +#if LCD_DEPTH == 1 + id = _GREY_MULUQ(_grey_info.width, yd & ~7) + (~yd & 7); + is = _GREY_MULUQ(_grey_info.width, ys & ~7) + (~ys & 7); +#elif LCD_DEPTH == 2 + id = _GREY_MULUQ(_grey_info.width, yd & ~3) + (~yd & 3); + is = _GREY_MULUQ(_grey_info.width, ys & ~3) + (~ys & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + dst = &_grey_info.data[id].value; + src = &_grey_info.data[is].value; + dst_end = dst + _grey_info.width * _GREY_X_ADVANCE; + + do + { + *dst = *src; + dst += _GREY_X_ADVANCE; + src += _GREY_X_ADVANCE; + } + while (dst < dst_end); + } + for (; yd >= 0; yd--) + { +#if LCD_PIXELFORMAT == HORIZONTAL_PACKING + id = _GREY_MULUQ(_grey_info.width, yd); +#else +#if LCD_DEPTH == 1 + id = _GREY_MULUQ(_grey_info.width, yd & ~7) + (~yd & 7); +#elif LCD_DEPTH == 2 + id = _GREY_MULUQ(_grey_info.width, yd & ~3) + (~yd & 3); +#endif +#endif /* LCD_PIXELFORMAT */ + dst = &_grey_info.data[id].value; + dst_end = dst + _grey_info.width * _GREY_X_ADVANCE; + + do + { + *dst = blank; + dst += _GREY_X_ADVANCE; + } + while (dst < dst_end); + } +} + +#endif /* !SIMULATOR */ |