summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/playergfx.h
blob: 9f1305af1216490339c619751c11b1b0484feeba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/***************************************************************************
*             __________               __   ___.
*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
*                     \/            \/     \/    \/            \/
* $Id$
*
* Bitmap graphics on player LCD!
*
* 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.
*
****************************************************************************/

#ifndef __PGFX_H__
#define __PGFX_H__

#include "plugin.h"

#ifdef HAVE_LCD_CHARCELLS /* Player only :) */

bool pgfx_init(int cwidth, int cheight);
void pgfx_release(void);
void pgfx_display(int cx, int cy);
void pgfx_display_block(int cx, int cy, int x, int y);
void pgfx_update(void);

void pgfx_set_drawmode(int mode);
int  pgfx_get_drawmode(void);

void pgfx_clear_display(void);
void pgfx_drawpixel(int x, int y);
void pgfx_drawline(int x1, int y1, int x2, int y2);
void pgfx_hline(int x1, int x2, int y);
void pgfx_vline(int x, int y1, int y2);
void pgfx_drawrect(int x, int y, int width, int height);
void pgfx_fillrect(int x, int y, int width, int height);
void pgfx_bitmap_part(const unsigned char *src, int src_x, int src_y,
                      int stride, int x, int y, int width, int height);
void pgfx_bitmap(const unsigned char *src, int x, int y, int width, int height);

#define pgfx_mono_bitmap_part pgfx_bitmap_part
#define pgfx_mono_bitmap pgfx_bitmap

#endif /* HAVE_LCD_CHARCELLS */
#endif /* __PGFX_H__ */
ef='#n276'>276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
/***************************************************************************
*             __________               __   ___.
*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
*                     \/            \/     \/    \/            \/
* $Id$
*
* Additional LCD routines not present in the rockbox core
* Drawing 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"

/* sort the given coordinates by increasing x value */
static void sort_points_by_increasing_x(int* x1, int* y1,
                                        int* x2, int* y2,
                                        int* x3, int* y3)
{
    int x, y;
    if (*x1 > *x3)
    {
        if (*x2 < *x3)       /* x2 < x3 < x1 */
        {
            x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
            y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
        }
        else if (*x2 > *x1)  /* x3 < x1 < x2 */
        {
            x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
            y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
        }
        else               /* x3 <= x2 <= x1 */
        {
            x = *x1; *x1 = *x3; *x3 = x;
            y = *y1; *y1 = *y3; *y3 = y;
        }
    }
    else
    {
        if (*x2 < *x1)       /* x2 < x1 <= x3 */
        {
            x = *x1; *x1 = *x2; *x2 = x;
            y = *y1; *y1 = *y2; *y2 = y;
        }
        else if (*x2 > *x3)  /* x1 <= x3 < x2 */
        {
            x = *x2; *x2 = *x3; *x3 = x;
            y = *y2; *y2 = *y3; *y3 = y;
        }
        /* else already sorted */
    }
}

#define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \
    sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3)

/* draw a filled triangle, using horizontal lines for speed */
static void xlcd_filltriangle_horizontal(struct screen* display,
                                         int x1, int y1,
                                         int x2, int y2,
                                         int x3, int y3)
{
    long fp_x1, fp_x2, fp_dx1, fp_dx2;
    int y;
    sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);

    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++)
            {
                display->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++)
            {
                display->hline(fp_x1 >> 16, fp_x2 >> 16, y);
                fp_x1 += fp_dx1;
                fp_x2 += fp_dx2;
            }
        }
    }
}

/* draw a filled triangle, using vertical lines for speed */
static void xlcd_filltriangle_vertical(struct screen* display,
                                       int x1, int y1,
                                       int x2, int y2,
                                       int x3, int y3)
{
    long fp_y1, fp_y2, fp_dy1, fp_dy2;
    int x;
    sort_points_by_increasing_x(&x1, &y1, &x2, &y2, &x3, &y3);

    if (x1 < x3)  /* draw */
    {
        fp_dy1 = ((y3 - y1) << 16) / (x3 - x1);
        fp_y1  = (y1 << 16) + (1<<15) + (fp_dy1 >> 1);

        if (x1 < x2)  /* first part */
        {
            fp_dy2 = ((y2 - y1) << 16) / (x2 - x1);
            fp_y2  = (y1 << 16) + (1<<15) + (fp_dy2 >> 1);
            for (x = x1; x < x2; x++)
            {
                display->vline(x, fp_y1 >> 16, fp_y2 >> 16);
                fp_y1 += fp_dy1;
                fp_y2 += fp_dy2;
            }
        }
        if (x2 < x3)  /* second part */
        {
            fp_dy2 = ((y3 - y2) << 16) / (x3 - x2);
            fp_y2 = (y2 << 16) + (1<<15) + (fp_dy2 >> 1);
            for (x = x2; x < x3; x++)
            {
                display->vline(x, fp_y1 >> 16, fp_y2 >> 16);
                fp_y1 += fp_dy1;
                fp_y2 += fp_dy2;
            }
        }
    }
}

void xlcd_filltriangle(int x1, int y1,
                       int x2, int y2,
                       int x3, int y3)
{
    /* default is main screen */
    xlcd_filltriangle_screen(rb->screens[SCREEN_MAIN],
                             x1, y1, x2, y2, x3, y3);
}

void xlcd_filltriangle_screen(struct screen* display,
                              int x1, int y1,
                              int x2, int y2,
                              int x3, int y3)
{
    if(display->pixel_format==HORIZONTAL_PACKING || display->depth>=8)
        xlcd_filltriangle_horizontal(display, x1, y1, x2, y2, x3, y3);
    else
        xlcd_filltriangle_vertical(display, x1, y1, x2, y2, x3, y3);
}

#if LCD_DEPTH >= 8

#ifdef HAVE_LCD_COLOR
static const fb_data graylut[256] = {
#if LCD_PIXELFORMAT == RGB565
    0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0821, 0x0821, 0x0841,
    0x0841, 0x0841, 0x0841, 0x0861, 0x0861, 0x1062, 0x1062, 0x1082,
    0x1082, 0x1082, 0x1082, 0x10a2, 0x10a2, 0x18a3, 0x18a3, 0x18c3,
    0x18c3, 0x18c3, 0x18c3, 0x18e3, 0x18e3, 0x20e4, 0x20e4, 0x2104,
    0x2104, 0x2104, 0x2104, 0x2124, 0x2124, 0x2124, 0x2925, 0x2945,
    0x2945, 0x2945, 0x2945, 0x2965, 0x2965, 0x2965, 0x3166, 0x3186,
    0x3186, 0x3186, 0x3186, 0x31a6, 0x31a6, 0x31a6, 0x39a7, 0x39c7,
    0x39c7, 0x39c7, 0x39c7, 0x39e7, 0x39e7, 0x39e7, 0x41e8, 0x4208,
    0x4208, 0x4208, 0x4208, 0x4228, 0x4228, 0x4228, 0x4a29, 0x4a49,
    0x4a49, 0x4a49, 0x4a49, 0x4a69, 0x4a69, 0x4a69, 0x4a69, 0x528a,
    0x528a, 0x528a, 0x528a, 0x52aa, 0x52aa, 0x52aa, 0x52aa, 0x5aab,
    0x5acb, 0x5acb, 0x5acb, 0x5acb, 0x5aeb, 0x5aeb, 0x5aeb, 0x62ec,
    0x630c, 0x630c, 0x630c, 0x630c, 0x632c, 0x632c, 0x632c, 0x6b2d,
    0x6b4d, 0x6b4d, 0x6b4d, 0x6b4d, 0x6b6d, 0x6b6d, 0x6b6d, 0x6b6d,
    0x738e, 0x738e, 0x738e, 0x738e, 0x73ae, 0x73ae, 0x73ae, 0x73ae,
    0x7bcf, 0x7bcf, 0x7bcf, 0x7bcf, 0x7bef, 0x7bef, 0x7bef, 0x7bef,
    0x8410, 0x8410, 0x8410, 0x8410, 0x8430, 0x8430, 0x8430, 0x8430,
    0x8c51, 0x8c51, 0x8c51, 0x8c51, 0x8c71, 0x8c71, 0x8c71, 0x8c71,
    0x9492, 0x9492, 0x9492, 0x9492, 0x94b2, 0x94b2, 0x94b2, 0x94b2,
    0x94d2, 0x9cd3, 0x9cd3, 0x9cd3, 0x9cf3, 0x9cf3, 0x9cf3, 0x9cf3,
    0x9d13, 0xa514, 0xa514, 0xa514, 0xa534, 0xa534, 0xa534, 0xa534,
    0xa554, 0xad55, 0xad55, 0xad55, 0xad55, 0xad75, 0xad75, 0xad75,
    0xad75, 0xb596, 0xb596, 0xb596, 0xb596, 0xb5b6, 0xb5b6, 0xb5b6,
    0xb5b6, 0xb5d6, 0xbdd7, 0xbdd7, 0xbdd7, 0xbdf7, 0xbdf7, 0xbdf7,
    0xbdf7, 0xbe17, 0xc618, 0xc618, 0xc618, 0xc638, 0xc638, 0xc638,
    0xc638, 0xc658, 0xce59, 0xce59, 0xce59, 0xce79, 0xce79, 0xce79,
    0xce79, 0xce99, 0xd69a, 0xd69a, 0xd69a, 0xd6ba, 0xd6ba, 0xd6ba,
    0xd6ba, 0xd6da, 0xd6da, 0xdedb, 0xdedb, 0xdefb, 0xdefb, 0xdefb,
    0xdefb, 0xdf1b, 0xdf1b, 0xe71c, 0xe71c, 0xe73c, 0xe73c, 0xe73c,
    0xe73c, 0xe75c, 0xe75c, 0xef5d, 0xef5d, 0xef7d, 0xef7d, 0xef7d,
    0xef7d, 0xef9d, 0xef9d, 0xf79e, 0xf79e, 0xf7be, 0xf7be, 0xf7be,
    0xf7be, 0xf7de, 0xf7de, 0xffdf, 0xffdf, 0xffff, 0xffff, 0xffff
#elif LCD_PIXELFORMAT == RGB565SWAPPED
    0x0000, 0x0000, 0x0000, 0x2000, 0x2000, 0x2108, 0x2108, 0x4108,
    0x4108, 0x4108, 0x4108, 0x6108, 0x6108, 0x6210, 0x6210, 0x8210,
    0x8210, 0x8210, 0x8210, 0xa210, 0xa210, 0xa318, 0xa318, 0xc318,
    0xc318, 0xc318, 0xc318, 0xe318, 0xe318, 0xe420, 0xe420, 0x0421,
    0x0421, 0x0421, 0x0421, 0x2421, 0x2421, 0x2421, 0x2529, 0x4529,
    0x4529, 0x4529, 0x4529, 0x6529, 0x6529, 0x6529, 0x6631, 0x8631,
    0x8631, 0x8631, 0x8631, 0xa631, 0xa631, 0xa631, 0xa739, 0xc739,
    0xc739, 0xc739, 0xc739, 0xe739, 0xe739, 0xe739, 0xe841, 0x0842,
    0x0842, 0x0842, 0x0842, 0x2842, 0x2842, 0x2842, 0x294a, 0x494a,
    0x494a, 0x494a, 0x494a, 0x694a, 0x694a, 0x694a, 0x694a, 0x8a52,
    0x8a52, 0x8a52, 0x8a52, 0xaa52, 0xaa52, 0xaa52, 0xaa52, 0xab5a,
    0xcb5a, 0xcb5a, 0xcb5a, 0xcb5a, 0xeb5a, 0xeb5a, 0xeb5a, 0xec62,
    0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x2c63, 0x2c63, 0x2c63, 0x2d6b,
    0x4d6b, 0x4d6b, 0x4d6b, 0x4d6b, 0x6d6b, 0x6d6b, 0x6d6b, 0x6d6b,
    0x8e73, 0x8e73, 0x8e73, 0x8e73, 0xae73, 0xae73, 0xae73, 0xae73,
    0xcf7b, 0xcf7b, 0xcf7b, 0xcf7b, 0xef7b, 0xef7b, 0xef7b, 0xef7b,
    0x1084, 0x1084, 0x1084, 0x1084, 0x3084, 0x3084, 0x3084, 0x3084,
    0x518c, 0x518c, 0x518c, 0x518c, 0x718c, 0x718c, 0x718c, 0x718c,
    0x9294, 0x9294, 0x9294, 0x9294, 0xb294, 0xb294, 0xb294, 0xb294,
    0xd294, 0xd39c, 0xd39c, 0xd39c, 0xf39c, 0xf39c, 0xf39c, 0xf39c,
    0x139d, 0x14a5, 0x14a5, 0x14a5, 0x34a5, 0x34a5, 0x34a5, 0x34a5,
    0x54a5, 0x55ad, 0x55ad, 0x55ad, 0x55ad, 0x75ad, 0x75ad, 0x75ad,
    0x75ad, 0x96b5, 0x96b5, 0x96b5, 0x96b5, 0xb6b5, 0xb6b5, 0xb6b5,
    0xb6b5, 0xd6b5, 0xd7bd, 0xd7bd, 0xd7bd, 0xf7bd, 0xf7bd, 0xf7bd,
    0xf7bd, 0x17be, 0x18c6, 0x18c6, 0x18c6, 0x38c6, 0x38c6, 0x38c6,
    0x38c6, 0x58c6, 0x59ce, 0x59ce, 0x59ce, 0x79ce, 0x79ce, 0x79ce,
    0x79ce, 0x99ce, 0x9ad6, 0x9ad6, 0x9ad6, 0xbad6, 0xbad6, 0xbad6,
    0xbad6, 0xdad6, 0xdad6, 0xdbde, 0xdbde, 0xfbde, 0xfbde, 0xfbde,
    0xfbde, 0x1bdf, 0x1bdf, 0x1ce7, 0x1ce7, 0x3ce7, 0x3ce7, 0x3ce7,
    0x3ce7, 0x5ce7, 0x5ce7, 0x5def, 0x5def, 0x7def, 0x7def, 0x7def,
    0x7def, 0x9def, 0x9def, 0x9ef7, 0x9ef7, 0xbef7, 0xbef7, 0xbef7,
    0xbef7, 0xdef7, 0xdef7, 0xdfff, 0xdfff, 0xffff, 0xffff, 0xffff
#endif /* LCD_PIXELFORMAT */
};
#endif /* HAVE_LCD_COLOR */

/* Draw a partial greyscale bitmap, canonical 8 bit format */
void xlcd_gray_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;
    fb_data *dst;

    /* nothing to draw? */
    if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_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 > LCD_WIDTH)
        width = LCD_WIDTH - x;
    if (y + height > LCD_HEIGHT)
        height = LCD_HEIGHT - y;

    src    += stride * src_y + src_x; /* move starting point */
    src_end = src + stride * height;
    dst     = rb->lcd_framebuffer + LCD_WIDTH * y + x;

    do
    {
        const unsigned char *src_row = src;
        const unsigned char *row_end = src_row + width;
        fb_data *dst_row = dst;

#ifdef HAVE_LCD_COLOR
        do
            *dst_row++ = graylut[*src_row++];
        while (src_row < row_end);
#endif

        src +=  stride;
        dst += LCD_WIDTH;
    }
    while (src < src_end);
}

/* Draw a full greyscale bitmap, canonical 8 bit format */
void xlcd_gray_bitmap(const unsigned char *src, int x, int y, int width,
                      int height)
{
    xlcd_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
}

#ifdef HAVE_LCD_COLOR
/* Draw a partial colour bitmap, canonical 24 bit RGB format */
void xlcd_color_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;
    fb_data *dst;

    /* nothing to draw? */
    if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_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 > LCD_WIDTH)
        width = LCD_WIDTH - x;
    if (y + height > LCD_HEIGHT)
        height = LCD_HEIGHT - y;

    src    += 3 * (stride * src_y + src_x); /* move starting point */
    src_end = src + 3 * stride * height;
    dst     = rb->lcd_framebuffer + LCD_WIDTH * y + x;

    do
    {
        const unsigned char *src_row = src;
        const unsigned char *row_end = src_row + 3 * width;
        fb_data *dst_row = dst;

        do
        {   /* only RGB565 and RGB565SWAPPED so far */
            unsigned red   = 31 * (*src_row++) + 127;
            unsigned green = 63 * (*src_row++) + 127;
            unsigned blue  = 31 * (*src_row++) + 127;

            red   = (red + (red >> 8)) >> 8;     /* approx red /= 255: */
            green = (green + (green >> 8)) >> 8; /* approx green /= 255: */
            blue  = (blue + (blue >> 8)) >> 8;   /* approx blue /= 255: */

#if LCD_PIXELFORMAT == RGB565
            *dst_row++ = (red << 11) | (green << 5) | blue;
#elif LCD_PIXELFORMAT == RGB565SWAPPED
            *dst_row++ = swap16((red << 11) | (green << 5) | blue);
#endif
        }
        while (src_row < row_end);

        src +=  3 * stride;
        dst += LCD_WIDTH;
    }
    while (src < src_end);
}

/* Draw a full colour bitmap, canonical 24 bit RGB format */
void xlcd_color_bitmap(const unsigned char *src, int x, int y, int width,
                       int height)
{
    xlcd_color_bitmap_part(src, 0, 0, width, x, y, width, height);
}
#endif /* HAVE_LCD_COLOR */

#endif /* LCD_DEPTH >= 8 */

#endif /* HAVE_LCD_BITMAP */