KSM edits to RA8875

Dependents:   Liz_Test_Code

GraphicsDisplay.cpp

Committer:
WiredHome
Date:
2014-01-20
Revision:
31:c72e12cd5c67
Parent:
29:422616aa04bd
Child:
32:0e4f2ae512e2

File content as of revision 31:c72e12cd5c67:

/* mbed GraphicsDisplay Display Library Base Class
 * Copyright (c) 2007-2009 sford
 * Released under the MIT License: http://mbed.org/license/mit
 */

#include "GraphicsDisplay.h"
#include "Bitmap.h"

#define DEBUG "GD"
// ...
// INFO("Stuff to show %d", var); // new-line is automatically appended
//
#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
void HexDump(char * title, uint8_t * p, int count)
{
    int i;
    char buf[100] = "0000: ";
    
    if (*title)
        INFO("%s", title);
    for (i=0; i<count; ) {
        sprintf(buf + strlen(buf), "%02X ", *(p+i));
        if ((++i & 0x0F) == 0x00) {
            INFO("%s", buf);
            if (i < count)
                sprintf(buf, "%04X: ", i);
            else
                buf[0] = '\0';
        }
    }
    if (strlen(buf))
        INFO("%s", buf);
}
#else
#define INFO(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#define HexDump(a, b)
#endif

// #define LOCALFONT

#ifdef LOCALFONT
const unsigned char FONT8x8[97][8] = {
    0x08, 0x08, 0x08, 0X00, 0X00, 0X00, 0X00, 0X00, // columns, rows, num_bytes_per_char
    0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // space 0x20
    0x30, 0x78, 0x78, 0x30, 0x30, 0X00, 0x30, 0X00, // !
    0x6C, 0x6C, 0x6C, 0X00, 0X00, 0X00, 0X00, 0X00, // "
    0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0X00, // #
    0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0X00, // $
    0X00, 0x63, 0x66, 0x0C, 0x18, 0x33, 0x63, 0X00, // %
    0x1C, 0x36, 0x1C, 0x3B, 0x6E, 0x66, 0x3B, 0X00, // &
    0x30, 0x30, 0x60, 0X00, 0X00, 0X00, 0X00, 0X00, // '
    0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0X00, // (
    0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0X00, // )
    0X00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0X00, 0X00, // *
    0X00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0X00, 0X00, // +
    0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0x30, // ,
    0X00, 0X00, 0X00, 0x7E, 0X00, 0X00, 0X00, 0X00, // -
    0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0X00, // .
    0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0X00, // / (forward slash)
    0x3E, 0x63, 0x63, 0x6B, 0x63, 0x63, 0x3E, 0X00, // 0 0x30
    0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x7E, 0X00, // 1
    0x3C, 0x66, 0x06, 0x1C, 0x30, 0x66, 0x7E, 0X00, // 2
    0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0X00, // 3
    0x0E, 0x1E, 0x36, 0x66, 0x7F, 0x06, 0x0F, 0X00, // 4
    0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0X00, // 5
    0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0X00, // 6
    0x7E, 0x66, 0x06, 0x0C, 0x18, 0x18, 0x18, 0X00, // 7
    0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0X00, // 8
    0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0X00, // 9
    0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0X00, // :
    0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0x30, // ;
    0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0X00, // <
    0X00, 0X00, 0x7E, 0X00, 0X00, 0x7E, 0X00, 0X00, // =
    0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0X00, // >
    0x3C, 0x66, 0x06, 0x0C, 0x18, 0X00, 0x18, 0X00, // ?
    0x3E, 0x63, 0x6F, 0x69, 0x6F, 0x60, 0x3E, 0X00, // @ 0x40
    0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0X00, // A
    0x7E, 0x33, 0x33, 0x3E, 0x33, 0x33, 0x7E, 0X00, // B
    0x1E, 0x33, 0x60, 0x60, 0x60, 0x33, 0x1E, 0X00, // C
    0x7C, 0x36, 0x33, 0x33, 0x33, 0x36, 0x7C, 0X00, // D
    0x7F, 0x31, 0x34, 0x3C, 0x34, 0x31, 0x7F, 0X00, // E
    0x7F, 0x31, 0x34, 0x3C, 0x34, 0x30, 0x78, 0X00, // F
    0x1E, 0x33, 0x60, 0x60, 0x67, 0x33, 0x1F, 0X00, // G
    0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0X00, // H
    0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // I
    0x0F, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0X00, // J
    0x73, 0x33, 0x36, 0x3C, 0x36, 0x33, 0x73, 0X00, // K
    0x78, 0x30, 0x30, 0x30, 0x31, 0x33, 0x7F, 0X00, // L
    0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0X00, // M
    0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x63, 0X00, // N
    0x3E, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0X00, // O
    0x7E, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x78, 0X00, // P 0x50
    0x3C, 0x66, 0x66, 0x66, 0x6E, 0x3C, 0x0E, 0X00, // Q
    0x7E, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x73, 0X00, // R
    0x3C, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x3C, 0X00, // S
    0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // T
    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0X00, // U
    0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // V
    0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0X00, // W
    0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0X00, // X
    0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0X00, // Y
    0x7F, 0x63, 0x46, 0x0C, 0x19, 0x33, 0x7F, 0X00, // Z
    0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0X00, // [
    0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0X00, // \ (back slash)
    0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0X00, // ]
    0x08, 0x1C, 0x36, 0x63, 0X00, 0X00, 0X00, 0X00, // ^
    0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0xFF, // _
    0x18, 0x18, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, // ` 0x60
    0X00, 0X00, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0X00, // a
    0x70, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x6E, 0X00, // b
    0X00, 0X00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0X00, // c
    0x0E, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3B, 0X00, // d
    0X00, 0X00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0X00, // e
    0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0X00, // f
    0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x7C, // g
    0x70, 0x30, 0x36, 0x3B, 0x33, 0x33, 0x73, 0X00, // h
    0x18, 0X00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0X00, // i
    0x06, 0X00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, // j
    0x70, 0x30, 0x33, 0x36, 0x3C, 0x36, 0x73, 0X00, // k
    0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // l
    0X00, 0X00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0X00, // m
    0X00, 0X00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0X00, // n
    0X00, 0X00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0X00, // o
    0X00, 0X00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78, // p
    0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F, // q
    0X00, 0X00, 0x6E, 0x3B, 0x33, 0x30, 0x78, 0X00, // r
    0X00, 0X00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0X00, // s
    0x08, 0x18, 0x3E, 0x18, 0x18, 0x1A, 0x0C, 0X00, // t
    0X00, 0X00, 0x66, 0x66, 0x66, 0x66, 0x3B, 0X00, // u
    0X00, 0X00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // v
    0X00, 0X00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0X00, // w
    0X00, 0X00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0X00, // x
    0X00, 0X00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x7C, // y
    0X00, 0X00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0X00, // z
    0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0X00, // {
    0x0C, 0x0C, 0x0C, 0X00, 0x0C, 0x0C, 0x0C, 0X00, // |
    0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0X00, // }
    0x3B, 0x6E, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // ~
    0x1C, 0x36, 0x36, 0x1C, 0X00, 0X00, 0X00, 0X00  // DEL
}; 
#endif // LOCALFONT

GraphicsDisplay::GraphicsDisplay(const char *name) 
    : TextDisplay(name)
{
    font = NULL;
    //foreground(0xFFFF);
    //background(0x0000);
}

RetCode_t GraphicsDisplay::set_font(const unsigned char * _font)
{
    font = _font;
    INFO("set_font(%lu) %lu", _font, font);
    return noerror;     // trusting them, but it might be good to put some checks in here...
}

#ifdef LOCALFONT
int GraphicsDisplay::character(int x, int y, int value)
{
    INFO("character(%d,%d,%c)", x, t, value);
    if (value <= 0x1F && value >= 7F)
        return 0;
    
    return blitbit(x, y, FONT8X8[0][0], FONT8X8[0][1], 
        (char *)&(FONT8x8[value - 0x1F][0]));
}
#else
int GraphicsDisplay::character(int x, int y, int c)
{
    unsigned int offset;
    const unsigned char * charRecord;
 
    if (c <= 0x1F || c >= 0x7F)
        return 0;
    offset = font[0];                    // bytes / char
    charRecord = &font[((c - ' ') * offset) + 4];      // start of char bitmap
    return fontblit(x, y, font, charRecord);
}
#endif

void GraphicsDisplay::window(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
    // current pixel location
    _x = x;
    _y = y;
    // window settings
    _x1 = x;
    _x2 = x + w - 1;
    _y1 = y;
    _y2 = y + h - 1;
}

void GraphicsDisplay::WindowMax(void)
{
    window(0,0, width(),height());
}

void GraphicsDisplay::putp(color_t colour)
{
    // put pixel at current pixel location
    pixel(_x, _y, colour);
    // update pixel location based on window settings
    _x++;
    if(_x > _x2) {
        _x = _x1;
        _y++;
        if(_y > _y2) {
            _y = _y1;
        }
    }
}

void GraphicsDisplay::fill(int x, int y, int w, int h, color_t colour)
{
    window(x, y, w, h);
    for(int i=0; i<w*h; i++) {
        putp(colour);
    }
}

RetCode_t GraphicsDisplay::cls()
{
    fill(0, 0, width(), height(), _background);
    return noerror;
}

void GraphicsDisplay::blit(int x, int y, int w, int h, const int * colour)
{
    window(x, y, w, h);
    for (int i=0; i<w*h; i++) {
        putp(colour[i]);
    }
}

int GraphicsDisplay::blitbit(int x, int y, int w, int h, const char * colour)
{
    _foreground = 0xFFFF;
    INFO("blitbit(%d,%d, %d,%d, %02X) [%04X,%04X]", x,y, w,h, *colour, _foreground, _background);
    INFO("%lu  %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
        colour,
        colour[0], colour[1], colour[2], colour[3], colour[4], colour[5], colour[6], colour[7], 
        colour[8], colour[9], colour[10], colour[11], colour[12], colour[13], colour[14], colour[15]);
    window(x, y, w, h);
    for (int i = 0; i < w*h; i++) {
        char byte = colour[i >> 3];
        int offset = i & 0x7;
        if (offset == 0)
            INFO(" %2d = %02X", i>>3, byte);
        int c = ((byte << offset) & 0x80) ? _foreground : _background;
        putp(c);
    }
    return w;
}


int GraphicsDisplay::fontblit(int x, int y, const unsigned char * fontTable, const unsigned char * fontChar)
{
    _foreground = 0xFFFF;
    //int fontWidth = font[1];                       // get hor size of font
    int fontHeight = font[2];                      // get vert size of font
    int bytesPerLine = font[3];                       // bytes per line
    int charWidth = fontChar[0];        // width of this character
    int px, py;
    window(x, y, charWidth, fontHeight);
    
    for (py = 0; py < fontHeight; py++) {
        int bitmask = 1 << (py & 7);
        
        for (px = 0; px < charWidth; px++) {
            int offset = (py / 8) + px * bytesPerLine;
            unsigned char byte = fontChar[offset + 1];  // skip the char's # bits wide value
            int c = (byte & bitmask) ? _foreground : _background;
            putp(c);
        }
    }
    return charWidth;
}

// BMP Color Palette is BGRx
//      BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000
// RGB16 is
//      RRRR RGGG GGGB BBBB
// swap to little endian
//      GGGB BBBB RRRR RGGG
color_t RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i)
{
    color_t c;
 
    c  = ((colorPalette[i].rgbBlue  >> 3) <<  0);
    c |= ((colorPalette[i].rgbGreen >> 2) <<  5);
    c |= ((colorPalette[i].rgbRed   >> 3) << 11);
    c = (c >> 8) | (c << 8);
    //INFO("B %02X G %02X R %02X c %04X", colorPalette[i].rgbBlue, colorPalette[i].rgbGreen, 
    //    colorPalette[i].rgbRed, c);
    return c;
}


RetCode_t GraphicsDisplay::BMP_16(unsigned int x, unsigned int y, const char *Name_BMP)
{
    #define OffsetPixelWidth    18
    #define OffsetPixelHeight   22
    #define OffsetFileSize      34
    #define OffsetPixData       10
    #define OffsetBPP           28

    char filename[50];
    BITMAPFILEHEADER BMP_Header;
    BITMAPINFOHEADER BMP_Info;
    RGBQUAD * colorPalette = NULL;
    int colorCount;
    char * lineBuffer = NULL;
    
    uint16_t BPP_t;
    uint32_t PixelWidth, PixelHeight;
    uint32_t start_data;
    unsigned int    i, offset;
    int padd,j;

    // get the filename
    LocalFileSystem local("local");
    sprintf(filename,"/local/%s", Name_BMP);
    INFO("Opening {%s}", filename);
    FILE *Image = fopen(filename, "rb");  // open the bmp file
    if (!Image) {
        return(file_not_found);
    }

    fread(&BMP_Header, 1, sizeof(BMP_Header), Image);      // get the BMP Header
    INFO("bfType %04X", BMP_Header.bfType);
    //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
    if (BMP_Header.bfType != BF_TYPE) { // BMP_Header[0] != 0x42 || BMP_Header[1] != 0x4D) {  // check magic byte
        fclose(Image);
        return(not_bmp_format);     // error no BMP file
    }

    fread(&BMP_Info, 1, sizeof(BMP_Info), Image);
    //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
    BPP_t = BMP_Info.biBitCount;
    INFO("biBitCount %04X", BPP_t);
    if (BPP_t != 4 && BPP_t != 8 && BPP_t != 16) {   // Support 4, 8, 16-bits per pixel
        fclose(Image);
        return(not_supported_format);
    }

    //PixelHeight = BMP_Header[OffsetPixelHeight] + (BMP_Header[OffsetPixelHeight + 1] << 8) + (BMP_Header[OffsetPixelHeight + 2] << 16) + (BMP_Header[OffsetPixelHeight + 3] << 24);
    //PixelWidth = BMP_Header[OffsetPixelWidth] + (BMP_Header[OffsetPixelWidth + 1] << 8) + (BMP_Header[OffsetPixelWidth + 2] << 16) + (BMP_Header[OffsetPixelWidth + 3] << 24);
    PixelHeight = BMP_Info.biHeight;
    PixelWidth = BMP_Info.biWidth;
    if (PixelHeight > height() + y || PixelWidth > width() + x) {
        fclose(Image);
        return(image_too_big);
    }
    INFO("(%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight);

    if (BMP_Info.biBitCount <= 8) {
        int paletteSize;
        // Read the color palette
        colorCount = 1 << BMP_Info.biBitCount;
        paletteSize = sizeof(RGBQUAD) * colorCount;
        //INFO("colors: %d, paletteSize: %d", colorCount, paletteSize);
        colorPalette = (RGBQUAD *)malloc(paletteSize);
        if (colorPalette == NULL) {
            fclose(Image);
            return(not_enough_ram);
        }
        fread(colorPalette, 1, paletteSize, Image);
        HexDump("Color Palette", (uint8_t *)colorPalette, paletteSize);
    } else {
        ERR("Bits per pixel > 8 [%d]", BMP_Info.biBitCount);
    }

    //start_data = BMP_Header[OffsetPixData] + (BMP_Header[OffsetPixData + 1] << 8) + (BMP_Header[OffsetPixData + 2] << 16) + (BMP_Header[OffsetPixData + 3] << 24);
    start_data = BMP_Header.bfOffBits;

    //HexDump("Raw Data", (uint8_t *)&start_data, 32);
    int lineBufSize = ((BPP_t * PixelWidth + 31)/32)*4;
    //INFO("lineBufSize = %d", lineBufSize);
    lineBuffer = (char *)malloc(lineBufSize);
    if (lineBuffer == NULL) {
        free(colorPalette);
        fclose(Image);
        return(not_enough_ram);
    }

    // the bmp lines are padded to multiple of 4 bytes
    padd = -1;
    do {
        padd++;
    } while ((PixelWidth * sizeof(color_t) + padd) % 4 != 0);

    // Define window for top to bottom and left to right
    window(x,y, PixelWidth,PixelHeight);
    //INFO("(%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight);
    for (j = PixelHeight - 1; j >= 0; j--) {               //Lines bottom up
        //INFO("line %d", j);
        offset = start_data + j * (lineBufSize + padd);   // start of line
        fseek(Image, offset, SEEK_SET);
        fread(lineBuffer, 1, lineBufSize, Image);       // read a line - slow !
        //HexDump("Line", (uint8_t *)lineBuffer, lineBufSize);
        for (i = 0; i < PixelWidth; i++) {        // copy pixel data to TFT
            if (BPP_t == 4) {
                uint8_t dPix = lineBuffer[i/2];
                if ((i & 1) == 0)
                    dPix >>= 4;
                dPix &= 0x0F;
                color_t color;
                color = RGBQuadToRGB16(colorPalette, dPix);
                putp(color);
            } else if (BPP_t == 8) {
                color_t color;
                color = RGBQuadToRGB16(colorPalette, lineBuffer[i]);
                putp(color);
            } else if (BPP_t == 16) {
                putp(lineBuffer[i] & 0xFF);
                putp(lineBuffer[i] >> 8);
            }
        }
    }
    free(lineBuffer);
    free(colorPalette);
    fclose(Image);
    //INFO("Freed and closed");
    WindowMax();
    return(noerror);
}

int GraphicsDisplay::columns()
{
    return width() / 8;
}

int GraphicsDisplay::rows()
{
    return height() / 8;
}