summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/gray_core.c
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2004-06-23 22:15:50 +0000
committerJens Arnold <amiconn@rockbox.org>2004-06-23 22:15:50 +0000
commit7c6bdd64935452464b21f99198896c34569105e5 (patch)
treebecd4aeb5498966aea5629f1e692ba5131192b5e /apps/plugins/lib/gray_core.c
parent8877ad943eb077d10a0725b47c55a8b2f55f319a (diff)
Split grayscale library into several files to make up a real function library. Significantly decreases binary size for plugins using it.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4802 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/lib/gray_core.c')
-rw-r--r--apps/plugins/lib/gray_core.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/apps/plugins/lib/gray_core.c b/apps/plugins/lib/gray_core.c
new file mode 100644
index 0000000000..b582cd801a
--- /dev/null
+++ b/apps/plugins/lib/gray_core.c
@@ -0,0 +1,252 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+* $Id$
+*
+* Grayscale framework
+* Core functions
+*
+* This is a generic framework to use grayscale display within Rockbox
+* plugins. It obviously does not work for the player.
+*
+* Copyright (C) 2004 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 SIMULATOR /* not for simulator by now */
+#include "plugin.h"
+
+#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
+#include "gray.h"
+
+/* Global variables */
+struct plugin_api *_gray_rb = NULL; /* global api struct pointer */
+_tGraybuf *_graybuf = NULL; /* pointer to grayscale buffer */
+short _gray_random_buffer; /* buffer for random number generator */
+
+/* Prototypes */
+static void _timer_isr(void);
+
+/* timer interrupt handler: display next bitplane */
+static void _timer_isr(void)
+{
+ _gray_rb->lcd_blit(_graybuf->data + MULU16(_graybuf->plane_size,
+ _graybuf->cur_plane), _graybuf->x, _graybuf->by,
+ _graybuf->width, _graybuf->bheight, _graybuf->width);
+
+ if (++_graybuf->cur_plane >= _graybuf->depth)
+ _graybuf->cur_plane = 0;
+
+ if (_graybuf->flags & _GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
+ {
+ int x1 = MAX(_graybuf->x, 0);
+ int x2 = MIN(_graybuf->x + _graybuf->width, LCD_WIDTH);
+ int y1 = MAX(_graybuf->by << 3, 0);
+ int y2 = MIN((_graybuf->by << 3) + _graybuf->height, LCD_HEIGHT);
+
+ if (y1 > 0) /* refresh part above overlay, full width */
+ _gray_rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
+
+ if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
+ _gray_rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
+
+ if (x1 > 0) /* refresh part to the left of overlay */
+ _gray_rb->lcd_update_rect(0, y1, x1, y2 - y1);
+
+ if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
+ _gray_rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
+
+ _graybuf->flags &= ~_GRAY_DEFERRED_UPDATE; /* clear request */
+ }
+}
+
+/*---------------------------------------------------------------------------
+ Initialize the framework
+ ----------------------------------------------------------------------------
+ Every framework needs such a function, and it has to be called as
+ the very first one */
+void gray_init(struct plugin_api* newrb)
+{
+ _gray_rb = newrb;
+}
+
+/*---------------------------------------------------------------------------
+ Prepare the grayscale display buffer
+ ----------------------------------------------------------------------------
+ arguments:
+ gbuf = pointer to the memory area to use (e.g. plugin buffer)
+ gbuf_size = max usable size of the buffer
+ width = width in pixels (1..112)
+ bheight = height in 8-pixel units (1..8)
+ depth = desired number of shades - 1 (1..32)
+
+ result:
+ = depth if there was enough memory
+ < depth if there wasn't enough memory. The number of displayable
+ shades is smaller than desired, but it still works
+ = 0 if there wasn't even enough memory for 1 bitplane (black & white)
+
+ You can request any depth from 1 to 32, not just powers of 2. The routine
+ performs "graceful degradation" if the memory is not sufficient for the
+ desired depth. As long as there is at least enough memory for 1 bitplane,
+ it creates as many bitplanes as fit into memory, although 1 bitplane will
+ only deliver black & white display.
+
+ If you need info about the memory taken by the grayscale buffer, supply an
+ int* as the last parameter. This int will then contain the number of bytes
+ used. The total memory needed can be calculated as follows:
+ total_mem =
+ sizeof(_tGraybuf) (= 64 bytes currently)
+ + sizeof(long) (= 4 bytes)
+ + (width * bheight + sizeof(long)) * depth
+ + 0..3 (longword alignment of grayscale display buffer)
+ */
+int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
+ int bheight, int depth, int *buf_taken)
+{
+ int possible_depth, plane_size;
+ int i, j, align;
+
+ if ((unsigned) width > LCD_WIDTH
+ || (unsigned) bheight > (LCD_HEIGHT/8)
+ || depth < 1)
+ return 0;
+
+ /* the buffer has to be long aligned */
+ align = 3 - (((unsigned long)gbuf + 3) & 3);
+ gbuf += align;
+ gbuf_size -= align;
+
+ plane_size = MULU16(width, bheight);
+ possible_depth = (gbuf_size - sizeof(_tGraybuf) - sizeof(long))
+ / (plane_size + sizeof(long));
+
+ if (possible_depth < 1)
+ return 0;
+
+ depth = MIN(depth, 32);
+ depth = MIN(depth, possible_depth);
+
+ _graybuf = (_tGraybuf *) gbuf; /* global pointer to buffer structure */
+
+ _graybuf->x = 0;
+ _graybuf->by = 0;
+ _graybuf->width = width;
+ _graybuf->height = bheight << 3;
+ _graybuf->bheight = bheight;
+ _graybuf->plane_size = plane_size;
+ _graybuf->depth = depth;
+ _graybuf->cur_plane = 0;
+ _graybuf->flags = 0;
+ _graybuf->bitpattern = (unsigned long *) (gbuf + sizeof(_tGraybuf));
+ _graybuf->data = (unsigned char *) (_graybuf->bitpattern + depth + 1);
+
+ i = depth - 1;
+ j = 8;
+ while (i != 0)
+ {
+ i >>= 1;
+ j--;
+ }
+ _graybuf->randmask = 0xFFu >> j;
+
+ /* initial state is all white */
+ _gray_rb->memset(_graybuf->data, 0, MULU16(depth, plane_size));
+
+ /* Precalculate the bit patterns for all possible pixel values */
+ for (i = 0; i <= depth; i++)
+ {
+ unsigned long pattern = 0;
+ int value = 0;
+
+ for (j = 0; j < depth; j++)
+ {
+ pattern <<= 1;
+ value += i;
+
+ if (value >= depth)
+ value -= depth; /* "white" bit */
+ else
+ pattern |= 1; /* "black" bit */
+ }
+ /* now the lower <depth> bits contain the pattern */
+
+ _graybuf->bitpattern[i] = pattern;
+ }
+
+ _graybuf->fg_pattern = _graybuf->bitpattern[0]; /* black */
+ _graybuf->bg_pattern = _graybuf->bitpattern[depth]; /* white */
+ _graybuf->drawmode = GRAY_DRAW_SOLID;
+ _graybuf->curfont = FONT_SYSFIXED;
+
+ if (buf_taken) /* caller requested info about space taken */
+ {
+ *buf_taken = sizeof(_tGraybuf) + sizeof(long)
+ + MULU16(plane_size + sizeof(long), depth) + align;
+ }
+
+ return depth;
+}
+
+/*---------------------------------------------------------------------------
+ Release the grayscale display buffer
+ ----------------------------------------------------------------------------
+ Switches the grayscale overlay off at first if it is still running,
+ then sets the pointer to NULL.
+ DO CALL either this function or at least gray_show_display(false)
+ before you exit, otherwise nasty things may happen.
+ */
+void gray_release_buffer(void)
+{
+ gray_show_display(false);
+ _graybuf = NULL;
+}
+
+/*---------------------------------------------------------------------------
+ Switch the grayscale overlay on or off
+ ----------------------------------------------------------------------------
+ enable = true: the grayscale overlay is switched on if initialized
+ = false: the grayscale overlay is switched off and the regular lcd
+ content is restored
+
+ DO NOT call lcd_update() or any other api function that directly accesses
+ the lcd while the grayscale overlay is running! If you need to do
+ lcd_update() to update something outside the grayscale overlay area, use
+ gray_deferred_update() instead.
+
+ Other functions to avoid are:
+ lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
+ lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
+
+ The grayscale display consumes ~50 % CPU power (for a full screen overlay,
+ less if the overlay is smaller) when switched on. You can switch the overlay
+ on and off as many times as you want.
+ */
+void gray_show_display(bool enable)
+{
+ if (enable)
+ {
+ _graybuf->flags |= _GRAY_RUNNING;
+ _gray_rb->plugin_register_timer(FREQ / 67, 1, _timer_isr);
+ }
+ else
+ {
+ _gray_rb->plugin_unregister_timer();
+ _graybuf->flags &= ~_GRAY_RUNNING;
+ _gray_rb->lcd_update(); /* restore whatever there was before */
+ }
+}
+
+#endif // #ifdef HAVE_LCD_BITMAP
+#endif // #ifndef SIMULATOR
+