rockbox/apps/plugins/lib/xlcd_scroll.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

633 lines
20 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Additional LCD routines not present in the rockbox core
* Scrolling functions
*
* Copyright (C) 2005 Jens Arnold
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP
#include "xlcd.h"
#if (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
static const unsigned short patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
#endif
#if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) && (LCD_DEPTH < 8)
/* Scroll left */
void xlcd_scroll_left(int count)
{
int bitcount, oldmode;
int blockcount, blocklen;
if ((unsigned) count >= LCD_WIDTH)
return;
#if LCD_DEPTH == 2
blockcount = count >> 2;
blocklen = LCD_FBWIDTH - blockcount;
bitcount = 2 * (count & 3);
#endif
if (blockcount)
{
unsigned char *data = _xlcd_rb->lcd_framebuffer;
unsigned char *data_end = data + LCD_FBWIDTH*LCD_HEIGHT;
do
{
_xlcd_rb->memmove(data, data + blockcount, blocklen);
data += LCD_FBWIDTH;
}
while (data < data_end);
}
if (bitcount)
{
int bx, y;
unsigned char *addr = _xlcd_rb->lcd_framebuffer + blocklen;
#if LCD_DEPTH == 2
unsigned fill = 0x55 * (~_xlcd_rb->lcd_get_background() & 3);
#endif
for (y = 0; y < LCD_HEIGHT; y++)
{
unsigned char *row_addr = addr;
unsigned data = fill;
for (bx = 0; bx < blocklen; bx++)
{
--row_addr;
data = (data >> 8) | (*row_addr << bitcount);
*row_addr = data;
}
addr += LCD_FBWIDTH;
}
}
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(LCD_WIDTH - count, 0, count, LCD_HEIGHT);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
/* Scroll right */
void xlcd_scroll_right(int count)
{
int bitcount, oldmode;
int blockcount, blocklen;
if ((unsigned) count >= LCD_WIDTH)
return;
#if LCD_DEPTH == 2
blockcount = count >> 2;
blocklen = LCD_FBWIDTH - blockcount;
bitcount = 2 * (count & 3);
#endif
if (blockcount)
{
unsigned char *data = _xlcd_rb->lcd_framebuffer;
unsigned char *data_end = data + LCD_FBWIDTH*LCD_HEIGHT;
do
{
_xlcd_rb->memmove(data + blockcount, data, blocklen);
data += LCD_FBWIDTH;
}
while (data < data_end);
}
if (bitcount)
{
int bx, y;
unsigned char *addr = _xlcd_rb->lcd_framebuffer + blockcount;
#if LCD_DEPTH == 2
unsigned fill = 0x55 * (~_xlcd_rb->lcd_get_background() & 3);
#endif
for (y = 0; y < LCD_HEIGHT; y++)
{
unsigned char *row_addr = addr;
unsigned data = fill;
for (bx = 0; bx < blocklen; bx++)
{
data = (data << 8) | *row_addr;
*row_addr = data >> bitcount;
row_addr++;
}
addr += LCD_FBWIDTH;
}
}
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, 0, count, LCD_HEIGHT);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
#else /* LCD_PIXELFORMAT vertical packed or >= 8bit / pixel */
/* Scroll left */
void xlcd_scroll_left(int count)
{
fb_data *data, *data_end;
int length, oldmode;
if ((unsigned)count >= LCD_WIDTH)
return;
data = _xlcd_rb->lcd_framebuffer;
data_end = data + LCD_WIDTH*LCD_FBHEIGHT;
length = LCD_WIDTH - count;
do
{
_xlcd_rb->memmove(data, data + count, length * sizeof(fb_data));
data += LCD_WIDTH;
}
while (data < data_end);
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(length, 0, count, LCD_HEIGHT);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
/* Scroll right */
void xlcd_scroll_right(int count)
{
fb_data *data, *data_end;
int length, oldmode;
if ((unsigned)count >= LCD_WIDTH)
return;
data = _xlcd_rb->lcd_framebuffer;
data_end = data + LCD_WIDTH*LCD_FBHEIGHT;
length = LCD_WIDTH - count;
do
{
_xlcd_rb->memmove(data + count, data, length * sizeof(fb_data));
data += LCD_WIDTH;
}
while (data < data_end);
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, 0, count, LCD_HEIGHT);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
#endif /* LCD_PIXELFORMAT, LCD_DEPTH */
#if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) || (LCD_DEPTH >= 8)
/* Scroll up */
void xlcd_scroll_up(int count)
{
int length, oldmode;
if ((unsigned)count >= LCD_HEIGHT)
return;
length = LCD_HEIGHT - count;
_xlcd_rb->memmove(_xlcd_rb->lcd_framebuffer,
_xlcd_rb->lcd_framebuffer + count * LCD_FBWIDTH,
length * LCD_FBWIDTH * sizeof(fb_data));
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, length, LCD_WIDTH, count);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
/* Scroll down */
void xlcd_scroll_down(int count)
{
int length, oldmode;
if ((unsigned)count >= LCD_HEIGHT)
return;
length = LCD_HEIGHT - count;
_xlcd_rb->memmove(_xlcd_rb->lcd_framebuffer + count * LCD_FBWIDTH,
_xlcd_rb->lcd_framebuffer,
length * LCD_FBWIDTH * sizeof(fb_data));
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, 0, LCD_WIDTH, count);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
#else /* LCD_PIXELFORMAT == VERTICAL_PACKING,
LCD_PIXELFORMAT == VERTICAL_INTERLEAVED */
/* Scroll up */
void xlcd_scroll_up(int count)
{
int bitcount, oldmode;
int blockcount, blocklen;
if ((unsigned) count >= LCD_HEIGHT)
return;
#if (LCD_DEPTH == 1) \
|| (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
blockcount = count >> 3;
bitcount = count & 7;
#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
blockcount = count >> 2;
bitcount = 2 * (count & 3);
#endif
blocklen = LCD_FBHEIGHT - blockcount;
if (blockcount)
{
_xlcd_rb->memmove(_xlcd_rb->lcd_framebuffer,
_xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH,
blocklen * LCD_FBWIDTH * sizeof(fb_data));
}
if (bitcount)
{
#if LCD_PIXELFORMAT == VERTICAL_PACKING
#if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
asm (
"mov #0,r4 \n" /* x = 0 */
"mova .su_shifttbl,r0 \n" /* calculate jump destination for */
"mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
"bra .su_cloop \n" /* skip table */
"add r0,%[cnt] \n"
".align 2 \n"
".su_shifttbl: \n" /* shift jump offset table */
".byte .su_shift0 - .su_shifttbl \n"
".byte .su_shift1 - .su_shifttbl \n"
".byte .su_shift2 - .su_shifttbl \n"
".byte .su_shift3 - .su_shifttbl \n"
".byte .su_shift4 - .su_shifttbl \n"
".byte .su_shift5 - .su_shifttbl \n"
".byte .su_shift6 - .su_shifttbl \n"
".byte .su_shift7 - .su_shifttbl \n"
".su_cloop: \n" /* repeat for every column */
"mov %[addr],r2 \n" /* get start address */
"mov #0,r3 \n" /* current_row = 0 */
"mov #0,r1 \n" /* fill with zero */
".su_iloop: \n" /* repeat for all rows */
"sub %[wide],r2 \n" /* address -= width */
"mov.b @r2,r0 \n" /* get data byte */
"shll8 r1 \n" /* old data to 2nd byte */
"extu.b r0,r0 \n" /* extend unsigned */
"or r1,r0 \n" /* combine old data */
"jmp @%[cnt] \n" /* jump into shift "path" */
"extu.b r0,r1 \n" /* store data for next round */
".su_shift6: \n" /* shift right by 0..7 bits */
"shll2 r0 \n"
"bra .su_shift0 \n"
"shlr8 r0 \n"
".su_shift4: \n"
"shlr2 r0 \n"
".su_shift2: \n"
"bra .su_shift0 \n"
"shlr2 r0 \n"
".su_shift7: \n"
"shlr2 r0 \n"
".su_shift5: \n"
"shlr2 r0 \n"
".su_shift3: \n"
"shlr2 r0 \n"
".su_shift1: \n"
"shlr r0 \n"
".su_shift0: \n"
"mov.b r0,@r2 \n" /* store data */
"add #1,r3 \n" /* current_row++ */
"cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
"bt .su_iloop \n"
"add #1,%[addr] \n" /* start_address++ */
"add #1,r4 \n" /* x++ */
"cmp/hi r4,%[wide] \n" /* x < width ? */
"bt .su_cloop \n"
: /* outputs */
: /* inputs */
[addr]"r"(_xlcd_rb->lcd_framebuffer + blocklen * LCD_FBWIDTH),
[wide]"r"(LCD_FBWIDTH),
[rows]"r"(blocklen),
[cnt] "r"(bitcount)
: /* clobbers */
"r0", "r1", "r2", "r3", "r4"
);
#elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
asm (
"move.l %[wide],%%d3\n" /* columns = width */
".su_cloop: \n" /* repeat for every column */
"move.l %[addr],%%a1\n" /* get start address */
"move.l %[rows],%%d2\n" /* rows = row_count */
"move.l %[bkg],%%d1 \n" /* fill with background */
".su_iloop: \n" /* repeat for all rows */
"sub.l %[wide],%%a1\n" /* address -= width */
"clr.l %%d0 \n"
"move.b (%%a1),%%d0 \n" /* get data byte */
"lsl.l #8,%%d1 \n" /* old data to 2nd byte */
"or.l %%d1,%%d0 \n" /* combine old data */
"clr.l %%d1 \n"
"move.b %%d0,%%d1 \n" /* keep data for next round */
"lsr.l %[cnt],%%d0 \n" /* shift right */
"move.b %%d0,(%%a1) \n" /* store data */
"subq.l #1,%%d2 \n" /* rows-- */
"bne.b .su_iloop \n"
"addq.l #1,%[addr] \n" /* start_address++ */
"subq.l #1,%%d3 \n" /* columns-- */
"bne.b .su_cloop \n"
: /* outputs */
: /* inputs */
[wide]"r"(LCD_FBWIDTH),
[rows]"r"(blocklen),
[addr]"a"(_xlcd_rb->lcd_framebuffer + blocklen * LCD_FBWIDTH),
[cnt] "d"(bitcount),
[bkg] "d"(0x55 * (~_xlcd_rb->lcd_get_background() & 3))
: /* clobbers */
"a1", "d0", "d1", "d2", "d3"
);
#else /* C version */
int x, by;
unsigned char *addr = _xlcd_rb->lcd_framebuffer + blocklen * LCD_FBWIDTH;
#if LCD_DEPTH == 2
unsigned fill = 0x55 * (~_xlcd_rb->lcd_get_background() & 3);
#else
const unsigned fill = 0;
#endif
for (x = 0; x < LCD_WIDTH; x++)
{
unsigned char *col_addr = addr++;
unsigned data = fill;
for (by = 0; by < blocklen; by++)
{
col_addr -= LCD_FBWIDTH;
data = (data << 8) | *col_addr;
*col_addr = data >> bitcount;
}
}
#endif /* CPU, LCD_DEPTH */
#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
#if LCD_DEPTH == 2
int x, by;
fb_data *addr = _xlcd_rb->lcd_framebuffer + blocklen * LCD_FBWIDTH;
unsigned fill, mask;
fill = patterns[_xlcd_rb->lcd_get_background() & 3] << 8;
mask = (0xFFu >> bitcount) << bitcount;
mask |= mask << 8;
for (x = 0; x < LCD_WIDTH; x++)
{
fb_data *col_addr = addr++;
unsigned olddata = fill;
unsigned data;
for (by = 0; by < blocklen; by++)
{
col_addr -= LCD_FBWIDTH;
data = *col_addr;
*col_addr = (olddata ^ ((data ^ olddata) & mask)) >> bitcount;
olddata = data << 8;
}
}
#endif /* LCD_DEPTH == 2 */
#endif /* LCD_PIXELFORMAT */
}
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, LCD_HEIGHT - count, LCD_WIDTH, count);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
/* Scroll up */
void xlcd_scroll_down(int count)
{
int bitcount, oldmode;
int blockcount, blocklen;
if ((unsigned) count >= LCD_HEIGHT)
return;
#if (LCD_DEPTH == 1) \
|| (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
blockcount = count >> 3;
bitcount = count & 7;
#elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
blockcount = count >> 2;
bitcount = 2 * (count & 3);
#endif
blocklen = LCD_FBHEIGHT - blockcount;
if (blockcount)
{
_xlcd_rb->memmove(_xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH,
_xlcd_rb->lcd_framebuffer,
blocklen * LCD_FBWIDTH * sizeof(fb_data));
}
if (bitcount)
{
#if LCD_PIXELFORMAT == VERTICAL_PACKING
#if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
asm (
"mov #0,r4 \n" /* x = 0 */
"mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
"mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
"bra .sd_cloop \n" /* skip table */
"add r0,%[cnt] \n"
".align 2 \n"
".sd_shifttbl: \n" /* shift jump offset table */
".byte .sd_shift0 - .sd_shifttbl \n"
".byte .sd_shift1 - .sd_shifttbl \n"
".byte .sd_shift2 - .sd_shifttbl \n"
".byte .sd_shift3 - .sd_shifttbl \n"
".byte .sd_shift4 - .sd_shifttbl \n"
".byte .sd_shift5 - .sd_shifttbl \n"
".byte .sd_shift6 - .sd_shifttbl \n"
".byte .sd_shift7 - .sd_shifttbl \n"
".sd_cloop: \n" /* repeat for every column */
"mov %[addr],r2 \n" /* get start address */
"mov #0,r3 \n" /* current_row = 0 */
"mov #0,r1 \n" /* fill with zero */
".sd_iloop: \n" /* repeat for all rows */
"shlr8 r1 \n" /* shift right to get residue */
"mov.b @r2,r0 \n" /* get data byte */
"jmp @%[cnt] \n" /* jump into shift "path" */
"extu.b r0,r0 \n" /* extend unsigned */
".sd_shift6: \n" /* shift left by 0..7 bits */
"shll8 r0 \n"
"bra .sd_shift0 \n"
"shlr2 r0 \n"
".sd_shift4: \n"
"shll2 r0 \n"
".sd_shift2: \n"
"bra .sd_shift0 \n"
"shll2 r0 \n"
".sd_shift7: \n"
"shll2 r0 \n"
".sd_shift5: \n"
"shll2 r0 \n"
".sd_shift3: \n"
"shll2 r0 \n"
".sd_shift1: \n"
"shll r0 \n"
".sd_shift0: \n"
"or r0,r1 \n" /* combine with last residue */
"mov.b r1,@r2 \n" /* store data */
"add %[wide],r2 \n" /* address += width */
"add #1,r3 \n" /* current_row++ */
"cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
"bt .sd_iloop \n"
"add #1,%[addr] \n" /* start_address++ */
"add #1,r4 \n" /* x++ */
"cmp/hi r4,%[wide] \n" /* x < width ? */
"bt .sd_cloop \n"
: /* outputs */
: /* inputs */
[addr]"r"(_xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH),
[wide]"r"(LCD_WIDTH),
[rows]"r"(blocklen),
[cnt] "r"(bitcount)
: /* clobbers */
"r0", "r1", "r2", "r3", "r4"
);
#elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
asm (
"move.l %[wide],%%d3\n" /* columns = width */
".sd_cloop: \n" /* repeat for every column */
"move.l %[addr],%%a1\n" /* get start address */
"move.l %[rows],%%d2\n" /* rows = row_count */
"move.l %[bkg],%%d1 \n" /* fill with background */
".sd_iloop: \n" /* repeat for all rows */
"lsr.l #8,%%d1 \n" /* shift right to get residue */
"clr.l %%d0 \n"
"move.b (%%a1),%%d0 \n" /* get data byte */
"lsl.l %[cnt],%%d0 \n"
"or.l %%d0,%%d1 \n" /* combine with last residue */
"move.b %%d1,(%%a1) \n" /* store data */
"add.l %[wide],%%a1\n" /* address += width */
"subq.l #1,%%d2 \n" /* rows-- */
"bne.b .sd_iloop \n"
"lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
"subq.l #1,%%d3 \n" /* columns-- */
"bne.b .sd_cloop \n"
: /* outputs */
: /* inputs */
[wide]"r"(LCD_WIDTH),
[rows]"r"(blocklen),
[addr]"a"(_xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH),
[cnt] "d"(bitcount),
[bkg] "d"((0x55 * (~_xlcd_rb->lcd_get_background() & 3)) << bitcount)
: /* clobbers */
"a1", "d0", "d1", "d2", "d3"
);
#else /* C version */
int x, by;
unsigned char *addr = _xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH;
#if LCD_DEPTH == 2
unsigned fill = (0x55 * (~_xlcd_rb->lcd_get_background() & 3)) << bitcount;
#else
const unsigned fill = 0;
#endif
for (x = 0; x < LCD_WIDTH; x++)
{
unsigned char *col_addr = addr++;
unsigned data = fill;
for (by = 0; by < blocklen; by++)
{
data = (data >> 8) | (*col_addr << bitcount);
*col_addr = data;
col_addr += LCD_FBWIDTH;
}
}
#endif /* CPU, LCD_DEPTH */
#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
#if LCD_DEPTH == 2
int x, by;
fb_data *addr = _xlcd_rb->lcd_framebuffer + blockcount * LCD_FBWIDTH;
unsigned fill, mask;
fill = patterns[_xlcd_rb->lcd_get_background() & 3] >> (8 - bitcount);
mask = (0xFFu >> bitcount) << bitcount;
mask |= mask << 8;
for (x = 0; x < LCD_WIDTH; x++)
{
fb_data *col_addr = addr++;
unsigned olddata = fill;
unsigned data;
for (by = 0; by < blocklen; by++)
{
data = *col_addr << bitcount;
*col_addr = olddata ^ ((data ^ olddata) & mask);
olddata = data >> 8;
col_addr += LCD_FBWIDTH;
}
}
#endif /* LCD_DEPTH == 2 */
#endif /* LCD_PIXELFORMAT */
}
oldmode = _xlcd_rb->lcd_get_drawmode();
_xlcd_rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
_xlcd_rb->lcd_fillrect(0, 0, LCD_WIDTH, count);
_xlcd_rb->lcd_set_drawmode(oldmode);
}
#endif /* LCD_PIXELFORMAT, LCD_DEPTH */
#endif /* HAVE_LCD_BITMAP */