Forked para SNOCC
Fork of RA8875 by
GraphicsDisplay.cpp
- Committer:
- WiredHome
- Date:
- 2016-01-17
- Revision:
- 101:e0aad446094a
- Parent:
- 100:0b084475d5a9
- Child:
- 104:8d1d3832a215
File content as of revision 101:e0aad446094a:
/* mbed GraphicsDisplay Display Library Base Class * Copyright (c) 2007-2009 sford * Released under the MIT License: http://mbed.org/license/mit * * Derivative work by D.Smart 2014 */ #include "GraphicsDisplay.h" #include "Bitmap.h" #include "string.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__); static void HexDump(const char * title, const 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, c) #endif char mytolower(char a) { if (a >= 'A' && a <= 'Z') return (a - 'A' + 'a'); else return a; } /// mystrnicmp exists because not all compiler libraries have this function. /// /// Some have strnicmp, others _strnicmp, and others have C++ methods, which /// is outside the scope of this C-portable set of functions. /// /// @param l is a pointer to the string on the left /// @param r is a pointer to the string on the right /// @param n is the number of characters to compare /// @returns -1 if l < r /// @returns 0 if l == r /// @returns +1 if l > r /// int mystrnicmp(const char *l, const char *r, size_t n) { int result = 0; if (n != 0) { do { result = mytolower(*l++) - mytolower(*r++); } while ((result == 0) && (*l != '\0') && (--n > 0)); } if (result < -1) result = -1; else if (result > 1) result = 1; return result; } GraphicsDisplay::GraphicsDisplay(const char *name) : TextDisplay(name) { font = NULL; } RetCode_t GraphicsDisplay::SelectUserFont(const unsigned char * _font) { font = _font; // trusting them, but it might be good to put some checks in here... return noerror; } int GraphicsDisplay::character(int x, int y, int c) { return fontblit(x, y, c); } RetCode_t GraphicsDisplay::window(loc_t x, loc_t y, dim_t w, dim_t h) { // current pixel location _x = x; _y = y; // window settings _x1 = x; _x2 = x + w - 1; _y1 = y; _y2 = y + h - 1; return noerror; } RetCode_t GraphicsDisplay::WindowMax(void) { return window(0,0, width(),height()); } RetCode_t GraphicsDisplay::_putp(color_t color) { pixel(_x, _y, color); // update pixel location based on window settings _x++; if(_x > _x2) { _x = _x1; _y++; if(_y > _y2) { _y = _y1; } } return noerror; } RetCode_t GraphicsDisplay::fill(int x, int y, int w, int h, color_t color) { return fillrect(x,y, x+w, y+h, color); } RetCode_t GraphicsDisplay::cls(uint16_t layers) { return fill(0, 0, width(), height(), _background); } RetCode_t GraphicsDisplay::blit(int x, int y, int w, int h, const int * color) { window(x, y, w, h); _StartGraphicsStream(); for (int i=0; i<w*h; i++) { _putp(color[i]); } _EndGraphicsStream(); return WindowMax(); } // 8 byte "info" section //0x00, // unknown ???????? //0x00, // unknown ???????? //0x20,0x00, // First char 32 //0x7F,0x00, // Last char 127 //0x25, // Font Height 37 //0x00, // Unknown 0 ???????? // //0x01,0x88,0x01,0x00 // ' ' is 1 pixel wide, data is at offset 0x0188 //0x0B,0xAD,0x01,0x00 // '!' is 11 pixels wide, data is at offset 0x01AD //0x0D,0xF7,0x01,0x00 // '"' is 13 pixels wide, data is at offset 0x01F7 //... //0x00,... // ' ' data stream. //0x00,0x06,0x00,0x07,0x80,0x07,0xC0,0x07,0xC0,0x07,0xC0 // '!' //... const uint8_t * GraphicsDisplay::getCharMetrics(const unsigned char c, uint8_t * width, uint8_t * height) { uint16_t offsetToCharLookup; uint16_t firstChar = font[3] * 256 + font[2]; uint16_t lastChar = font[5] * 256 + font[4]; uint8_t charHeight = font[6]; const unsigned char * charRecord; // width, data, data, data, ... INFO("first:%d, last:%d, c:%d", firstChar, lastChar, c); if (c < firstChar || c > lastChar) return NULL; // advance zero pixels since it was unprintable... // 8 bytes of preamble to the first level lookup table offsetToCharLookup = 8 + 4 * (c - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 uint8_t charWidth = font[offsetToCharLookup]; charRecord = font + font[offsetToCharLookup + 2] * 256 + font[offsetToCharLookup + 1]; //INFO("hgt:%d, wdt:%d", charHeight, charWidth); if (width) *width = charWidth; if (height) *height = charHeight; return charRecord; } int GraphicsDisplay::fontblit(int x, int y, const unsigned char c) { #if 0 uint16_t offsetToCharLookup; uint16_t firstChar = font[3] * 256 + font[2]; uint16_t lastChar = font[5] * 256 + font[4]; uint8_t charHeight = font[6]; const unsigned char * charRecord; // width, data, data, data, ... INFO("first:%d, last:%d, c:%d", firstChar, lastChar, c); if (c < firstChar || c > lastChar) return 0; // advance zero pixels since it was unprintable... // 8 bytes of preamble to the first level lookup table offsetToCharLookup = 8 + 4 * (c - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 uint8_t charWidth = font[offsetToCharLookup]; charRecord = font + font[offsetToCharLookup + 2] * 256 + font[offsetToCharLookup + 1]; #endif const unsigned char * charRecord; // width, data, data, data, ... uint8_t charWidth, charHeight; charRecord = getCharMetrics(c, &charWidth, &charHeight); if (charRecord) { INFO("hgt:%d, wdt:%d", charHeight, charWidth); // clip to the edge of the screen //if (x + charWidth >= width()) // charWidth = width() - x; //if (y + charHeight >= height()) // charHeight = height() - y; window(x, y, charWidth, charHeight); _StartGraphicsStream(); while (charHeight--) { uint8_t pixels = charWidth; uint8_t bitmask = 0x01; while (pixels) { uint8_t byte = *charRecord; INFO("byte, mask: %02X, %02X", byte, bitmask); color_t c = (byte & bitmask) ? _foreground : _background; _putp(c); bitmask <<= 1; if (pixels > 1 && bitmask == 0) { bitmask = 0x01; charRecord++; } pixels--; } charRecord++; } _EndGraphicsStream(); WindowMax(); return charWidth; } else { return 0; } } // 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 GraphicsDisplay::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); return c; } // RGB16 little endian // GGGB BBBB RRRR RGGG // swap // RRRR RGGG GGGB BBBB // RRRR R // extend to BMP Color Palette is BGRx // BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000 RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c) { RGBQUAD q; memset(&q, 0, sizeof(q)); c = (c << 8) | (c >> 8); // swap q.rgbBlue = ((c & 0x001F) << 3) | (c & 0x07); /* Blue value */ q.rgbGreen = ((c & 0x07E0) >> 3) | ((c >> 9) & 0x03); /* Green value */ q.rgbRed = ((c & 0xF800) >> 8) | ((c >> 13) & 0x07); /* Red value */ q.rgbReserved = 0; return q; } RetCode_t GraphicsDisplay::_RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image) { BITMAPINFOHEADER BMP_Info; RGBQUAD * colorPalette = NULL; int colorCount; uint8_t * lineBuffer = NULL; color_t * pixelBuffer = NULL; uint16_t BPP_t; dim_t PixelWidth, PixelHeight; unsigned int i, offset; int padd,j; #ifdef DEBUG uint32_t start_data; #endif // Now, Read the bitmap info header 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 && BPP_t != 24) { // Support 4, 8, 16, 24-bits per pixel fclose(Image); return(not_supported_format); } PixelHeight = BMP_Info.biHeight; PixelWidth = BMP_Info.biWidth; INFO("(%d,%d) (%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight, width(), height()); if (PixelHeight > height() + y || PixelWidth > width() + x) { fclose(Image); return(image_too_big); } if (BMP_Info.biBitCount <= 8) { int paletteSize; // Read the color palette colorCount = 1 << BMP_Info.biBitCount; paletteSize = sizeof(RGBQUAD) * colorCount; 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); } int lineBufSize = ((BPP_t * PixelWidth + 7)/8); INFO("BPP_t %d, PixelWidth %d, lineBufSize %d", BPP_t, PixelWidth, lineBufSize); lineBuffer = (uint8_t *)malloc(lineBufSize); if (lineBuffer == NULL) { free(colorPalette); fclose(Image); return(not_enough_ram); } pixelBuffer = (color_t *)malloc(PixelWidth * sizeof(color_t)); if (pixelBuffer == NULL) { free(lineBuffer); if (colorPalette) free(colorPalette); fclose(Image); return(not_enough_ram); } // the Raw Data records are padded to a multiple of 4 bytes int recordSize = 2; if (BPP_t == 4) { recordSize = 1; } else if (BPP_t == 8) { recordSize = 1; } else if (BPP_t == 16) { recordSize = 2; } else if (BPP_t == 24) { recordSize = 3; } padd = -1; do { padd++; } while ((PixelWidth * recordSize + padd) % 4 != 0); // Define window for top to bottom and left to right so writing auto-wraps window(x,y, PixelWidth,PixelHeight); SetGraphicsCursor(x, y); _StartGraphicsStream(); //start_data = BMP_Header.bfOffBits; HexDump("Raw Data", (uint8_t *)&start_data, 32); INFO("(%d,%d) (%d,%d), [%d,%d]", x,y, PixelWidth,PixelHeight, lineBufSize, padd); for (j = PixelHeight - 1; j >= 0; j--) { //Lines bottom up offset = fileOffset + j * (lineBufSize + padd); // start of line fseek(Image, offset, SEEK_SET); fread(lineBuffer, 1, lineBufSize, Image); // read a line - slow ! //INFO("offset: %6X", offset); 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; pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix); } else if (BPP_t == 8) { pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]); } else if (BPP_t == 16) { pixelBuffer[i] = lineBuffer[i]; } else if (BPP_t == 24) { color_t color; color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]); pixelBuffer[i] = color; } } pixelStream(pixelBuffer, PixelWidth, x, y++); } _EndGraphicsStream(); WindowMax(); free(pixelBuffer); // don't leak memory free(lineBuffer); if (colorPalette) free(colorPalette); return (noerror); } RetCode_t GraphicsDisplay::RenderImageFile(loc_t x, loc_t y, const char *FileName) { if (mystrnicmp(FileName + strlen(FileName) - 4, ".bmp", 4) == 0) { return RenderBitmapFile(x,y,FileName); } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".ico", 4) == 0) { return RenderIconFile(x,y,FileName); } else { return not_supported_format; } } RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP) { BITMAPFILEHEADER BMP_Header; INFO("Opening {%s}", Name_BMP); FILE *Image = fopen(Name_BMP, "rb"); 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) { fclose(Image); return(not_bmp_format); } RetCode_t rt = _RenderBitmap(x, y, BMP_Header.bfOffBits, Image); if (rt != noerror) { return rt; } else { fclose(Image); return (noerror); } } RetCode_t GraphicsDisplay::RenderIconFile(loc_t x, loc_t y, const char *Name_ICO) { ICOFILEHEADER ICO_Header; ICODIRENTRY ICO_DirEntry; INFO("Opening {%s}", Name_ICO); FILE *Image = fopen(Name_ICO, "rb"); if (!Image) { return(file_not_found); } fread(&ICO_Header, 1, sizeof(ICO_Header), Image); // get the BMP Header HexDump("ICO_Header", (uint8_t *)&ICO_Header, sizeof(ICO_Header)); if (ICO_Header.Reserved_zero != 0 || ICO_Header.icType != IC_TYPE || ICO_Header.icImageCount == 0) { fclose(Image); return(not_ico_format); } // Read ONLY the first of n possible directory entries. fread(&ICO_DirEntry, 1, sizeof(ICO_DirEntry), Image); HexDump("ICO_DirEntry", (uint8_t *)&ICO_DirEntry, sizeof(ICO_DirEntry)); INFO("biBitCount %04X", ICO_DirEntry.biBitCount); if (ICO_DirEntry.biBitCount != 0) { // Expecting this to be zero for ico fclose(Image); return(not_supported_format); } RetCode_t rt = _RenderBitmap(x, y, ICO_DirEntry.bfOffBits, Image); if (rt == noerror) { fclose(Image); return (noerror); } else { return rt; } } int GraphicsDisplay::columns() { return width() / 8; } int GraphicsDisplay::rows() { return height() / 8; }