PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)
Dependents: YATTT sd_map_test cPong SnowDemo ... more
PokittoLib
Library for programming Pokitto hardware
How to Use
- Import this library to online compiler (see button "import" on the right hand side
- DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
- Change My_settings.h according to your project
- Start coding!
Diff: POKITTO_CORE/PokittoDisplay.cpp
- Revision:
- 6:72f87b7c7400
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/POKITTO_CORE/PokittoDisplay.cpp Wed Oct 11 20:35:52 2017 +0000 @@ -0,0 +1,2147 @@ +/**************************************************************************/ +/*! + @file PokittoDisplay.cpp + @author Jonne Valola + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2016, Jonne Valola + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + + +/* THE SEGMENT BELOW PERTAINS TO CIRCLE DRAWING FUNCTIONS ONLY +* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! +Copyright (c) 2013 Adafruit Industries. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "PokittoDisplay.h" +#include "Pokitto_settings.h" +#include "GBcompatibility.h" +#include "PokittoCore.h" +#include "PokittoSound.h" +#include <stdio.h> +#include <string.h> + +#ifndef POK_SIM +#include "HWLCD.h" +#else +#include "SimLCD.h" +#endif + +Pokitto::Core core; +Pokitto::Sound sound; + +using namespace Pokitto; + + + +uint8_t* Display::m_scrbuf; +uint8_t* Display::m_tileset; +uint8_t* Display::m_tilebuf; +uint8_t* Display::m_tilecolorbuf; +uint8_t Display::m_mode, Display::m_colordepth; +uint8_t Display::fontSize=1; +int16_t Display::cursorX,Display::cursorY; +uint16_t Display::m_w,Display::m_h; +uint8_t Display::fontWidth, Display::fontHeight; +bool Display::textWrap=true; + +uint8_t Display::persistence = 0; +uint16_t Display::color = 1; +uint16_t Display::bgcolor = 0; +uint16_t Display::invisiblecolor = 17; +uint16_t Display::directcolor=0xFFFF; +uint16_t Display::directbgcolor=0x0; + +uint16_t* Display::paletteptr; +uint16_t Display::palette[PALETTE_SIZE]; +const unsigned char* Display::font; +int8_t Display::adjustCharStep = 1; +int8_t Display::adjustLineStep = 1; +bool Display::fixedWidthFont = false; + +/** drawing canvas **/ +//uint8_t* Display::canvas; // points to the active buffer. if null, draw direct to screen + +/** screenbuffer **/ +uint8_t Display::bpp = POK_COLORDEPTH; +#ifndef POK_TILEDMODE +#if (POK_SCREENMODE == MODE_HI_MONOCHROME) + uint8_t Display::width = POK_LCD_W; + uint8_t Display::height = POK_LCD_H; + uint8_t Display::screenbuffer[((POK_LCD_H+1)*POK_LCD_W)*POK_COLORDEPTH/8]; // maximum resolution +#elif (POK_SCREENMODE == MODE_HI_4COLOR) + uint8_t Display::width = POK_LCD_W; + uint8_t Display::height = POK_LCD_H; + uint8_t __attribute__((section (".bss"))) Display::screenbuffer[((POK_LCD_H)*POK_LCD_W)/4]; // maximum resolution +#elif (POK_SCREENMODE == MODE_FAST_16COLOR) + uint8_t Display::width = POK_LCD_W/2; + uint8_t Display::height = POK_LCD_H/2; + uint8_t Display::screenbuffer[(((POK_LCD_H/2)+1)*POK_LCD_W/2)*POK_COLORDEPTH/8]; // half resolution +#elif (POK_SCREENMODE == MODE_HI_16COLOR) + uint8_t Display::width = POK_LCD_W; + uint8_t Display::height = POK_LCD_H; + uint8_t Display::screenbuffer[POK_LCD_H*POK_LCD_W/2]; // 4 bits per pixel +#elif (POK_SCREENMODE == MODE_LAMENES) + uint8_t Display::width = 128; + uint8_t Display::height = 120; + uint8_t Display::screenbuffer[((121)*128)*POK_COLORDEPTH/8]; // half resolution +#elif (POK_SCREENMODE == MODE_GAMEBOY) + uint8_t Display::width = 160; + uint8_t Display::height = 144; + uint8_t Display::screenbuffer[160*144/4]; +#else + uint8_t Display::width = 84; + uint8_t Display::height = 48; + uint8_t Display::screenbuffer[128*64]; // not needed because Gamebuino and Arduboy have their own buffer +#endif +#else //Tiledmode +#if (POK_SCREENMODE == MODE_TILED_1BIT) + uint8_t Display::width = POK_LCD_W; + uint8_t Display::height = POK_LCD_H; + uint8_t Display::screenbuffer[0]; +#else + uint8_t Display::width = POK_LCD_W; + uint8_t Display::height = POK_LCD_H; + uint8_t Display::screenbuffer[0]; +#endif +#endif //tiledmode + +// RLE decoding +#define RLE_ESC_EOL 0 +#define RLE_ESC_EOB 1 +#define RLE_ESC_OFFSET 2 + +Display::Display() { + m_scrbuf = screenbuffer; + setDefaultPalette(); + m_mode = 1; // direct printing on by default + m_w = POK_LCD_W; + m_h = POK_LCD_H; + setFont(DEFAULT_FONT); + invisiblecolor=17; + bgcolor=0; + if (POK_COLORDEPTH) m_colordepth = POK_COLORDEPTH; + else m_colordepth = 4; + #if POK_GAMEBUINO_SUPPORT + setColorDepth(1); + #endif // POK_GAMEBUINO_SUPPORT +} + +uint16_t Display::getWidth() { + return width; +} + +uint8_t Display::getNumberOfColors() { + return 1<<POK_COLORDEPTH; +} + +uint16_t Display::getHeight() { + return height; +} + +uint8_t Display::getColorDepth() { + return m_colordepth; +} + +void Display::setColorDepth(uint8_t v) { + if (v > POK_COLORDEPTH) v=POK_COLORDEPTH; + m_colordepth = v; +} + +void Display::clearLCD() { + lcdFillSurface(0); + setCursor(0,0); // old basic computer style +} + +void Display::fillLCD(uint16_t c) { + lcdFillSurface(c); +} + +void Display::directPixel(int16_t x, int16_t y, uint16_t color) { + lcdPixel(x,y,color); +} + +void Display::directRectangle(int16_t x, int16_t y,int16_t x2, int16_t y2, uint16_t color) { + lcdRectangle(x,y,x2,y2,color); +} + +void Display::begin() { + lcdInit(); +} + +void Display::setCursor(int16_t x,int16_t y) { + cursorX = x; + cursorY = y; +} + +void Display::update() { + +#if POK_SCREENMODE == MODE_GAMEBOY + lcdRefreshModeGBC(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_HI_4COLOR + lcdRefreshMode1(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_HI_16COLOR + lcdRefreshMode3(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_FAST_16COLOR + lcdRefreshMode2(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_GAMEBUINO_16COLOR + lcdRefreshGB(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_ARDUBOY_16COLOR + lcdRefreshAB(m_scrbuf, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_TILED_1BIT + lcdRefreshT1(m_tilebuf, m_tilecolorbuf, m_tileset, paletteptr); +#endif + +if (!persistence) clear(); + +/** draw volume bar if visible **/ +#if POK_SHOW_VOLUME > 0 +if (core.volbar_visible) { + core.drawvolbar(4,20,sound.getVolume(),true); + core.volbar_visible--; +} +#endif // POK_SHOW_VOLUME + +} + +void Display::directBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t depth, uint8_t scale) { + uint8_t w = *bitmap; + uint8_t h = *(bitmap + 1); + bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height + int16_t i, j; + int8_t byteNum, bitNum, byteWidth = (w + 7) >> 3; + + if (depth == 1) { + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + if (*(bitmap + j * byteWidth + byteNum) & (0x80 >> bitNum)) { //0x80 = B10000000 + if (scale==1) directPixel(x + i, y + j,directcolor); + else { + directPixel(x + i + i, y + j + j,directcolor); + directPixel(x + 1 + i + i, y + j + j,directcolor); + directPixel(x + i + i, y + j + j + 1,directcolor); + directPixel(x + i + i + 1 , y + j + j + 1,directcolor); + } + } + } + } + } else if (depth == 4) { + for (j = 0; j < h; j+=1) { + for (i = 0; i < w; i+=2) { + uint16_t col = paletteptr[*bitmap>>4]; //higher nibble + if (scale==2) { + directPixel(x + (i<<1), y + (j<<1),col); + directPixel(x + (i<<1) + 1, y + (j<<1),col); + directPixel(x + (i<<1) + 1, y + (j<<1) + 1,col); + directPixel(x + (i<<1), y + (j<<1) + 1,col); + } else directPixel(x + i, y + j,col); + col = paletteptr[*bitmap&0xF]; // lower nibble + if (scale==2) { + directPixel(x + (i<<1) + 2, y + (j<<1),col); + directPixel(x + (i<<1) + 1 + 2, y + (j<<1),col); + directPixel(x + (i<<1) + 1 + 2, y + (j<<1) + 1,col); + directPixel(x + (i<<1) + 2 , y + (j<<1) + 1,col); + } else directPixel(x + i + 1, y + j,col); + bitmap++; + } + } + } + +} + +int Display::directChar(int16_t x, int16_t y, uint16_t index){ + const uint8_t* bitmap = font; + uint8_t w = *bitmap; + uint8_t h = *(bitmap + 1); + uint8_t hbytes=0, xtra=1; + if (h==8 || h==16) xtra=0; //don't add if exactly on byte limit + hbytes=(h>>3)+xtra; //GLCD fonts are arranged w+1 times h/8 bytes + //bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !) + bitmap = bitmap + 4 + index * (w * hbytes + 1); //add an offset to the pointer (fonts !) + //int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + int8_t i, j, numBytes; + numBytes = *bitmap++; //first byte of char is the width in bytes + // GLCD fonts are arranged LSB = topmost pixel of char, so its easy to just shift through the column + uint16_t bitcolumn; //16 bits for 2x8 bit high characters + + for (i = 0; i < numBytes; i++) { + bitcolumn = *bitmap++; + if (hbytes == 2) bitcolumn |= (*bitmap++)<<8; // add second byte for 16 bit high fonts + for (j = 0; j < h; j++) { + if (bitcolumn&0x1) { + if (fontSize==2) { + directPixel(x + (i<<1) , y + (j<<1),directcolor); + directPixel(x + (i<<1)+1, y + (j<<1),directcolor); + directPixel(x + (i<<1) , y + (j<<1)+1,directcolor); + directPixel(x + (i<<1)+1, y + (j<<1)+1,directcolor); + } else directPixel(x + i, y + j,directcolor); + } else if (directbgcolor != invisiblecolor) { + if (fontSize==2) { + directPixel(x + (i<<1) , y + (j<<1),directbgcolor); + directPixel(x + (i<<1)+1, y + (j<<1),directbgcolor); + directPixel(x + (i<<1) , y + (j<<1)+1,directbgcolor); + directPixel(x + (i<<1)+1, y + (j<<1)+1,directbgcolor); + } else directPixel(x + i, y + j,directbgcolor); + } + bitcolumn>>=1; + } + } + return (numBytes+adjustCharStep)*fontSize; // for character stepping +} + +int Display::bufferChar(int16_t x, int16_t y, uint16_t index){ + const uint8_t* bitmap = font; + uint8_t w = *bitmap; + uint8_t h = *(bitmap + 1); + uint8_t hbytes=0, xtra=1; + if (h==8 || h==16) xtra=0; //don't add if exactly on byte limit + hbytes=(h>>3)+xtra; //GLCD fonts are arranged w+1 times h/8 bytes + //bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !) + bitmap = bitmap + 4 + index * (w * hbytes + 1); //add an offset to the pointer (fonts !) + //int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + int8_t i, j, numBytes; + numBytes = *bitmap++; //first byte of char is the width in bytes + // GLCD fonts are arranged LSB = topmost pixel of char, so its easy to just shift through the column + uint16_t bitcolumn; //16 bits for 2x8 bit high characters + + for (i = 0; i < numBytes; i++) { + bitcolumn = *bitmap++; + if (hbytes == 2) bitcolumn |= (*bitmap++)<<8; // add second byte for 16 bit high fonts + for (j = 0; j <= h; j++) { // was j<=h + #if PROJ_ARDUBOY > 0 + if (bitcolumn&0x1) { + drawPixel(x + i, y + 7 - j,color); + } else drawPixel(x + i, y + 7 - j,bgcolor); + bitcolumn>>=1; + #else + if (bitcolumn&0x1) { + drawPixel(x + i, y + j,color); + } else drawPixel(x + i, y + j,bgcolor); + bitcolumn>>=1; + #endif // PROJ_ARDUBOY + + } + } + + return numBytes+adjustCharStep; // for character stepping +} + +void Display::clear() { + + uint8_t c=0; + c = bgcolor & (PALETTE_SIZE-1) ; //don't let palette go out of bounds + if (bpp==1 && bgcolor) c=0xFF; // bgcolor !=0, set all pixels + else if (bpp==2) { + c = bgcolor & 0x3; + c = c | (c << 2); + c = c | (c << 4); + } else { + c = (c & 0x0F) | (c << 4); + } + uint16_t j = sizeof(screenbuffer); + memset((void*)m_scrbuf,c,j); + + setCursor(0,0); + +} + +void Display::scroll(int16_t pixelrows) { + uint16_t index = 0, index2,oc; + if (pixelrows==0) return; + if (pixelrows >= height) pixelrows=height-1; + if (bpp == 4) index2 = pixelrows*width/2; + else if (bpp == 2) index2 = pixelrows*width/4; + else return; + oc = color; + color = bgcolor; + if (pixelrows>0) { + for (uint16_t y=0;y<height-pixelrows;y++) { + for (uint16_t x=0;x<(width/8)*bpp;x++) screenbuffer[index++]=screenbuffer[index2++]; + } + fillRect(0,cursorY,width,height); + } else { + for (uint16_t y=pixelrows;y<height;y++) { + for (uint16_t x=0;x<(width*bpp)/8;x++) screenbuffer[index2++]=screenbuffer[index2]; + } + fillRect(0,0,width,pixelrows); + } + color=oc; +} + +void Display::fillScreen(uint16_t c) { + c = c & (PALETTE_SIZE-1) ; //don't let palette go out of bounds + if (bpp==1 && c) c=0xFF; // set all pixels + else if (bpp==2) { + c = bgcolor & 0x3; + c = c | (c << 2); + c = c | (c << 4); + } else { + c = (c & 0x0F) | (c << 4); + } + memset((void*)m_scrbuf,c,sizeof(screenbuffer)); +} + +void Display::setDefaultPalette() { + #if PICOPALETTE + loadRGBPalette(palettePico); + #else + loadRGBPalette(POK_DEFAULT_PALETTE); + #endif //PICOPALETTE +} + +void Display::setColor(uint8_t c) { + color = c & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit +} + +void Display::setColor(uint8_t c,uint8_t bgc){ + color = c & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit + bgcolor = bgc & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit +} + +void Display::setInvisibleColor(uint16_t c){ + invisiblecolor = c; // invisible color can have values beyond 255 for identification purposes +} + +uint8_t Display::getColor() { + return color; +} + +uint8_t Display::getBgColor() { + return bgcolor; +} + +uint16_t Display::getInvisibleColor() { + return invisiblecolor; +} + +void Display::drawPixel(int16_t x,int16_t y, uint8_t col) { + if (col==invisiblecolor) return; // do not draw transparent pixels + if ((uint16_t)x >= width || (uint16_t)y >= height) return; + col &= (PALETTE_SIZE-1); + #if POK_GAMEBUINO_SUPPORT >0 + + uint8_t c = col; + uint8_t ct = col; + + uint16_t bitptr=0; + for (uint8_t cbit=0;cbit<POK_COLORDEPTH;cbit++) { + c = ct & 1; // take the lowest bit of the color index number + if(c == 0){ //white - or actually "Clear bit" + m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] &= ~_BV(y % 8); + } else { //black - or actually "Set bit" + m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] |= _BV(y % 8); + } + ct >>=1; // shift to get next bit + bitptr += POK_BITFRAME; // move one screen worth of buffer forward to get to the next color bit + } // POK_COLOURDEPTH + + #else + #if POK_COLORDEPTH == 1 + if (col) {m_scrbuf[(y >> 3) * width + x] |= (0x80 >> (y & 7)); return;} + m_scrbuf[(y >> 3) * width + x] &= ~(0x80 >> (y & 7)); + #elif POK_COLORDEPTH == 2 + if (col) { + col &= 3; + } + uint16_t i = y*(width>>2) + (x>>2); + uint8_t pixel = m_scrbuf[i]; + uint8_t column = x&0x03; + if (column==3) pixel = (pixel&0xFC)|(col); // bits 0-1 + else if (column==2) pixel = (pixel&0xF3)|(col<<2); // bits 2-3 + else if (column==1) pixel = (pixel&0xCF)|(col<<4); // bits 4-5 + else pixel = (pixel&0x3F)|(col<<6); // bits 6-7 + m_scrbuf[i] = pixel; + #elif POK_COLORDEPTH == 3 + #elif POK_COLORDEPTH == 4 + uint16_t i = y*(width>>1) + (x>>1); + uint8_t pixel = m_scrbuf[i]; + if (x&1) pixel = (pixel&0xF0)|(col); + else pixel = (pixel&0x0F) | (col<<4); + m_scrbuf[i] = pixel; + #endif // POK_COLORDEPTH + #endif // POK_GAMEBUINO_SUPPORT +} + +void Display::drawPixel(int16_t x,int16_t y) { + if ((uint16_t)x >= width || (uint16_t)y >= height) return; + + #if POK_GAMEBUINO_SUPPORT > 0 + + uint8_t c = color; + uint8_t ct = color; + if(ct == INVERT){ + ct = !getPixel(x, y); //jonne - was c = !getP... + } + + uint16_t bitptr=0; + for (uint8_t cbit=0;cbit<POK_COLORDEPTH;cbit++) { + c = ct & 1; // take the lowest bit of the color index number + if(c == 0){ //white - or actually "Clear bit" + #if DISPLAY_ROT == NOROT + m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] &= ~_BV(y % 8); + #elif DISPLAY_ROT == ROTCCW + m_scrbuf[LCDHEIGHT - y - 1 + (x / 8) * LCDWIDTH_NOROT + bitptr] &= ~_BV(x % 8); + #elif DISPLAY_ROT == ROT180 + m_scrbuf[LCDWIDTH - x - 1 + ((LCDHEIGHT - y - 1) / 8) * LCDWIDTH_NOROT + bitptr] &= ~_BV((LCDHEIGHT - y - 1) % 8); + #elif DISPLAY_ROT == ROTCW + m_scrbuf[y + ((LCDWIDTH - x - 1) / 8) * LCDWIDTH_NOROT + bitbtr] &= ~_BV((LCDWIDTH - x - 1) % 8); + #endif + //return; //jonne + } else { //black - or actually "Set bit" + #if DISPLAY_ROT == NOROT + m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] |= _BV(y % 8); + #elif DISPLAY_ROT == ROTCCW + m_scrbuf[LCDHEIGHT - y - 1 + (x / 8) * LCDWIDTH_NOROT + bitptr] |= _BV(x % 8); + #elif DISPLAY_ROT == ROT180 + m_scrbuf[LCDWIDTH - x - 1 + ((LCDHEIGHT - y - 1) / 8) * LCDWIDTH_NOROT + bitptr] |= _BV((LCDHEIGHT - y - 1) % 8); + #elif DISPLAY_ROT == ROTCW + m_scrbuf[y + ((LCDWIDTH - x - 1) / 8) * LCDWIDTH_NOROT + bitptr] |= _BV((LCDWIDTH - x -1) % 8); + #endif + //return; //jonne + } + ct >>=1; // shift to get next bit + bitptr += POK_BITFRAME; // move one screen worth of buffer forward to get to the next color bit + } // POK_COLOURDEPTH + + #else + + /** NOT Gamebuino */ + #if POK_COLORDEPTH == 1 + if (color) {m_scrbuf[(y >> 3) * width + x] |= (0x80 >> (y & 7)); return;} + m_scrbuf[(y >> 3) * width + x] &= ~(0x80 >> (y & 7)); + #elif POK_COLORDEPTH == 2 + uint16_t i = y*(width>>2) + (x>>2); + uint8_t pixel = m_scrbuf[i]; + uint8_t column = x&0x03; + if (column==3) pixel = (pixel&0xFC)|(color); // bits 0-1 + else if (column==2) pixel = (pixel&0xF3)|(color<<2); // bits 2-3 + else if (column==1) pixel = (pixel&0xCF)|(color<<4); // bits 4-5 + else pixel = (pixel&0x3F)|(color<<6); // bits 6-7 + m_scrbuf[i] = pixel; + #elif POK_COLORDEPTH == 3 + #elif POK_COLORDEPTH == 4 + uint16_t i = y*(width>>1) + (x>>1); + uint8_t pixel = m_scrbuf[i]; + if (x&1) pixel = (pixel&0xF0)|(color); + else pixel = (pixel&0x0F) | (color<<4); + m_scrbuf[i] = pixel; + #endif // POK_COLORDEPTH + #endif // POK_GAMEBUINO_SUPPORT +} + +uint8_t Display::getPixel(int16_t x,int16_t y) { + if ((uint16_t)x >= width || (uint16_t)y >= height) return 0; + #if POK_GAMEBUINO_SUPPORT + uint8_t color=0; //jonne + for (uint8_t cbit=0; cbit<POK_COLORDEPTH;cbit++) { + color |= (m_scrbuf[x + (y / 8) * LCDWIDTH+POK_BITFRAME*cbit] >> (y % 8)) & 0x1 ; //jonne - added +504*cbit + } + return color; + #else + /** not gamebuino */ + #if POK_COLORDEPTH == 1 + return (m_scrbuf[(y >> 3) * width + x] & (0x80 >> (y & 7))) ? 1:0; + #elif POK_COLORDEPTH == 2 + uint16_t i = y*(width>>2) + (x>>2); + uint8_t pixel = m_scrbuf[i]; + uint8_t column = x&0x03; + if (column==0) return pixel & 0x03; // bits 0-1 + else if (column==1) return (pixel & 0x0C)>>2; // bits 2-3 + else if (column==2) return (pixel & 0x30)>>4; // bits 4-5 + else return pixel>>6;; // bits 6-7 + #elif POK_COLORDEPTH == 3 + #elif POK_COLORDEPTH == 4 + uint16_t i = y*(width>>1) + (x>>1); + uint8_t pixel = m_scrbuf[i]; + if (x&1) return pixel & 0x0F; + else return pixel>>4; + #endif // POK_COLORDEPTH + #endif // POK_GAMEBUINO_SUPPORT +} + +void Display::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { + if ((uint16_t)x0 >= width || (uint16_t)y0 >= height || (uint16_t)x1 >= width || (uint16_t)y1 >= height ) { + if (clipLine (&x0,&y0,&x1,&y1)==0) return; // line out of bounds + } + if (x0 == x1) + drawColumn(x0,y0,y1); + else if (y0 == y1) + drawRow(x0,x1,y0); + else { + int e; + signed int dx,dy,j, temp; + signed char s1,s2, xchange; + signed int x,y; + + x = x0; + y = y0; + + //take absolute value + if (x1 < x0) { + dx = x0 - x1; + s1 = -1; + } + else if (x1 == x0) { + dx = 0; + s1 = 0; + } + else { + dx = x1 - x0; + s1 = 1; + } + + if (y1 < y0) { + dy = y0 - y1; + s2 = -1; + } + else if (y1 == y0) { + dy = 0; + s2 = 0; + } + else { + dy = y1 - y0; + s2 = 1; + } + + xchange = 0; + + if (dy>dx) { + temp = dx; + dx = dy; + dy = temp; + xchange = 1; + } + + e = ((int)dy<<1) - dx; + + for (j=0; j<=dx; j++) { + drawPixel(x,y); + + if (e>=0) { + if (xchange==1) x = x + s1; + else y = y + s2; + e = e - ((int)dx<<1); + } + if (xchange==1) + y = y + s2; + else + x = x + s1; + e = e + ((int)dy<<1); + } + } +} + +uint8_t Display::clipLine(int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1){ + // Check X bounds + if (*x1<*x0) { + //std::swap (*x1,*x0); // swap so that we dont have to check x1 also + swapWT(int16_t*,x1,x0); + //std::swap (*y1,*y0); // y needs to be swaaped also + swapWT(int16_t*,y1,y0); + } + + if (*x0>=width) return 0; // whole line is out of bounds + + // Clip against X0 = 0 + if (*x0 < 0) { + if ( *x1 < 0) return 0; // nothing visible + int16_t dx = (*x1 - *x0); + int16_t dy = ((*y1 - *y0) << 8); // 8.8 fixed point calculation trick + int16_t m = dy/dx; + *y0 = *y0 + ((m*-*x0)>>8); // get y0 at boundary + *x0 = 0; + } + + // Clip against x1 = 83 + if (*x1 >= width) { + int16_t dx = (*x1 - *x0); + int16_t dy = ((*y1 - *y0) << 8); // 8.8 fixed point calculation trick + int16_t m = dy/dx; + //*y1 = *y1 + ((m*(*x1-XMAX))>>8); // get y0 at boundary + *y1 = *y1 + ((m*(width-1-*x1))>>8); // get y0 at boundary + *x1 = width-1; + } + + // Check Y bounds + if (*y1<*y0) { + //std::swap (*x1,*x0); // swap so that we dont have to check x1 also + swapWT(int16_t*,x1,x0); + //std::swap (*y1,*y0); // y needs to be swaaped also + swapWT(int16_t*,y1,y0); + } + + if (*y0>=height) return 0; // whole line is out of bounds + + if (*y0 < 0) { + if ( *y1 < 0) return 0; // nothing visible + int16_t dx = (*x1 - *x0) << 8; + int16_t dy = (*y1 - *y0); // 8.8 fixed point calculation trick + int16_t m = dx/dy; + *x0 = *x0 + ((m*-*y0)>>8); // get x0 at boundary + *y0 = 0; + } + + // Clip against y1 = 47 + if (*y1 >= height) { + int16_t dx = (*x1 - *x0) << 8; + int16_t dy = (*y1 - *y0); // 8.8 fixed point calculation trick + int16_t m = dx/dy; + *x1 = *x1 + ((m*(height-1-*y1))>>8); // get y0 at boundary + //*x1 = *x1 + ((m*(*y1-YMAX))>>8); // get y0 at boundary + *y1 = height-1; + } + return 1; // clipped succesfully +} + +void Display::map1BitColumn(int16_t x, int16_t sy, int16_t ey, const uint8_t* bitmap, uint16_t column){ + if ((uint16_t)sy>=height && (uint16_t)ey>=height) return; //completely out of bounds + if ((uint16_t)x>=width) return; //completely out of bounds + if (sy>ey) { + int y=sy; + sy=ey; + ey=y; // swap around so that x0 is less than x1 + } + uint16_t bmw,bmh; + float texelstep, texelindex; + bmw = *(bitmap); + bmh = *(bitmap+1); + if (column>bmw-1) column=bmw-1; + bitmap += 2; + bitmap += column; + texelstep = (float)bmh/((float)ey-(float)sy); + texelindex = 0; + for (int y=sy; y <= ey; y++, texelindex += texelstep) { + uint8_t texel; + uint8_t currbyte, bit; + currbyte = texelindex / 8; + bit = 7-((uint16_t) texelindex & 0x7); + texel=*(bitmap+currbyte*bmw); + if (texel & (1<<bit)) drawPixel(x,y); + else if (bgcolor != invisiblecolor) drawPixel(x,y,bgcolor); + } +}; + +void Display::drawColumn(int16_t x, int16_t sy, int16_t ey){ + if ((uint16_t)sy>=height && (uint16_t)ey>=height) return; //completely out of bounds + if ((uint16_t)x>=width) return; //completely out of bounds + if (sy>ey) { + int y=sy; + sy=ey; + ey=y; // swap around so that x0 is less than x1 + } + for (int y=sy; y <= ey; y++) { + drawPixel(x,y); + } +} + +void Display::drawRow(int16_t x0, int16_t x1, int16_t y){ + if ((uint16_t)x0>=width && (uint16_t)x1>=width) return; //completely out of bounds + if ((uint16_t)y>=height) return; //completely out of bounds + + if (x0>x1) { + int x=x0; + x0=x1; + x1=x; // swap around so that x0 is less than x1 + } + for (int x=x0; x <= x1; x++) { + drawPixel(x,y); + } +} + +void Display::drawFastVLine(int16_t x, int16_t y, int16_t h){ + if (h<0) {y += h; h = -h;} + drawColumn(x,y,y+h); +} + +void Display::drawFastHLine(int16_t x, int16_t y, int16_t w){ + if (w<0) {x += w; w = -w;} + drawRow(x,x+w-1,y); +} + +void Display::drawRectangle(int16_t x0, int16_t y0, int16_t w, int16_t h) { + drawColumn(x0,y0,y0+h); + drawColumn(x0+w,y0,y0+h); + drawRow(x0,x0+w,y0); + drawRow(x0,x0+w,y0+h); +} + +void Display::fillRectangle(int16_t x0,int16_t y0, int16_t w, int16_t h){ + int16_t x,y,x1,y1; + x1=x0+w;y1=y0+h; + if ((x0<0 && x1<0) || (x0>=width && x1 >=width)) return; //completely out of bounds + if ((y0<0 && y1<0) || (y0>=height && y1 >=height)) return; //completely out of bounds + if (x0>x1) {x=x1;x1=x0;} + else x=x0; + if (y0>y1) {y=y1;y1=y0;} + else y=y0; + if (x<0) x=0; + if (y<0) y=0; + for (;x<x1;x++) drawColumn(x,y,y1); +} + +void Display::fillRect(int16_t x, int16_t y, int16_t w, int16_t h) { + fillRectangle(x,y,w,h); +} + +void Display::drawRect(int16_t x, int16_t y, int16_t w, int16_t h) { + drawRectangle(x,y,w,h); +} + +void Display::drawCircle(int16_t x0, int16_t y0, int16_t r) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + drawPixel(x0, y0 + r); + drawPixel(x0, y0 - r); + drawPixel(x0 + r, y0); + drawPixel(x0 - r, y0); + + while (x < y) { + if (f >= 0) { + + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + drawPixel(x0 + x, y0 + y); + drawPixel(x0 - x, y0 + y); + drawPixel(x0 + x, y0 - y); + drawPixel(x0 - x, y0 - y); + drawPixel(x0 + y, y0 + x); + drawPixel(x0 - y, y0 + x); + drawPixel(x0 + y, y0 - x); + drawPixel(x0 - y, y0 - x); + + } +} + +void Display::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint16_t cornername) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + drawPixel(x0 + x, y0 + y); + drawPixel(x0 + y, y0 + x); + } + if (cornername & 0x2) { + drawPixel(x0 + x, y0 - y); + drawPixel(x0 + y, y0 - x); + } + if (cornername & 0x8) { + drawPixel(x0 - y, y0 + x); + drawPixel(x0 - x, y0 + y); + } + if (cornername & 0x1) { + + drawPixel(x0 - y, y0 - x); + drawPixel(x0 - x, y0 - y); + } + } +} + +void Display::fillCircle(int16_t x0, int16_t y0, int16_t r) { + drawFastVLine(x0, y0 - r, 2 * r ); + fillCircleHelper(x0, y0, r, 3, 0); +} + +void Display::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint16_t cornername, int16_t delta) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x1) { + drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta-1); //added -1 here, jonne + drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta-1); //added -1 here, jonne + } + if (cornername & 0x2) { + + drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta-1); //added -1 here, jonne + drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta-1); //added -1 here, jonne + } + } +} + +void Display::drawRoundRect(int16_t x, int16_t y, int16_t w,int16_t h, int16_t r) { + if (r<2) {drawRectangle(x,y,w,h);return;} + // smarter version + drawFastHLine(x + r, y, w - 2 * r); // Top + drawFastHLine(x + r, y + h - 1, w - 2 * r); // Bottom + drawFastVLine(x, y + r, h - 2 * r); // Left + drawFastVLine(x + w - 1, y + r, h - 2 * r); // Right + // draw four corners + drawCircleHelper(x + r, y + r, r, 1); + drawCircleHelper(x + w - r - 1, y + r, r, 2); + drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4); + drawCircleHelper(x + r, y + h - r - 1, r, 8); +} + +void Display::fillRoundRect(int16_t x, int16_t y, int16_t w,int16_t h, int16_t r) { + if (r<2) {fillRectangle(x,y,w,h);return;} + fillRectangle(x + r, y, w - 2 * r, h-1); + // draw four corners + fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1); + fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1); +} + +void Display::drawTriangle(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, + int16_t x2, int16_t y2) { + drawLine(x0, y0, x1, y1); + drawLine(x1, y1, x2, y2); + drawLine(x2, y2, x0, y0); +} + +void Display::fillTriangle(int16_t x0, int16_t y0, + int16_t x1, int16_t y1, + int16_t x2, int16_t y2) { + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + swapWT(int16_t,y0, y1); + swapWT(int16_t,x0, x1); + } + if (y1 > y2) { + swapWT(int16_t,y2, y1); + swapWT(int16_t,x2, x1); + } + if (y0 > y1) { + swapWT(int16_t,y0, y1); + swapWT(int16_t,x0, x1); + } + + if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if (x1 < a) a = x1; + else if (x1 > b) b = x1; + if (x2 < a) a = x2; + else if (x2 > b) b = x2; + drawFastHLine(a, y0, b - a + 1); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1, + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) last = y1; // Include y1 scanline + else last = y1 - 1; // Skip it + + for (y = y0; y <= last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) swapWT(int16_t,a, b); + drawFastHLine(a, y, b - a + 1); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for (; y <= y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + + if (a > b) swapWT(int16_t,a, b); + drawFastHLine(a, y, b - a + 1); + } +} + +void Display::setFont(const unsigned char * f) { + font = f; + fontWidth = *(font)+1; + fontHeight = *(font + 1)+1; +} + +void Display::drawMonoBitmap(int16_t x, int16_t y, const uint8_t* bitmap, uint8_t index) { + uint8_t w = *bitmap; + uint8_t h = *(bitmap + 1); + uint8_t xtra=0; + if (w&0x7) xtra=1; + bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !) + #if POK_GAMEBUINO_SUPPORT > 0 + int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + if (source & (0x80 >> bitNum)) { + drawPixel(x + i, y + j); + } + } + } + #else + /** not gamebuino */ + int8_t scrx,scry; + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + int8_t bitptr; + for (scry = y; scry < y+h; scry+=1) { + if ((x&1)==0) { /** EVEN pixel starting line**/ + for (scrx = x, bitptr=7; scrx < w+x; scrx+=2) { + uint8_t targetpixel = *scrptr; + if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF) | color<<4; // upper nibble + else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF) | bgcolor<<4; // upper nibble + bitptr--; + if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF0) | color; // lower nibble + else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF0) | bgcolor; // lower nibble + bitptr--; + if (bitptr<0) { bitptr = 7; bitmap++; } + *scrptr = targetpixel; + scrptr++; + } + } else { /** ODD pixel starting line **/ + for (scrx = x, bitptr=7; scrx < w+x; scrx+=2) { + uint8_t targetpixel = *scrptr; + // store higher nibble of source pixel in lower nibble of target + if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF0) | color; // lower nibble + else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF0) | bgcolor; // lower nibble + *scrptr = targetpixel; // store + bitptr--;scrptr++;targetpixel = *scrptr; + // store lower nibble of source pixel in higher nibble of target + if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF) | color<<4; // higher nibble + else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF) | bgcolor<<4; // higher nibble + *scrptr = targetpixel; // store + bitptr--; // do not increment scrptr here ! + } + } + if (bitptr!=7) bitmap++; // force skip to next line + // increment the y jump in the scrptr + scrptr = scrptr + ((width - w)>>1); + } + #endif // POK_GAMEBUINO_SUPPORT +} + + +void Display::drawBitmap(int16_t x, int16_t y, const uint8_t* bitmap, uint8_t frame) +{ + int16_t w = *bitmap; + int16_t h = *(bitmap + 1); + uint8_t framew = *(bitmap+2); + bitmap = bitmap + 3; //add an offset to the pointer to start after the width and height + /** visibility check */ + if (y<-h || y>height) return; //invisible + if (x<-framew || x>width) return; //invisible + /** 1 bpp mode */ + if (m_colordepth<2) { + int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + if (source & (0x80 >> bitNum)) { + drawPixel(x + i, y + j); + } + } + } + + return; + } + /** 2 bpp mode */ + if (m_colordepth<4) { + int16_t i, j, byteNum, bitNum, byteWidth = w >> 2; + for (i = 0; i < w; i++) { + byteNum = i / 4; + bitNum = (i % 4)<<1; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + uint8_t output = (source & (0xC0 >> bitNum)); + output >>= (6-bitNum); + if (output != invisiblecolor) { + setColor(output); + drawPixel(x + i, y + j); + } + } + } + + return; + } + /** 4bpp fast version */ + int16_t scrx,scry,xclip,xjump,scrxjump; + xclip=xjump=scrxjump=0; + bitmap += (framew*frame)>>1; + /** y clipping */ + if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;} + else if (y+h>height) { h -=(y-height);} + /** x clipping */ + xjump = (w-framew)>>1; + if (x<0) { xclip=(x&1)<<1; framew+=x; xjump = ((-x)>>1); bitmap += xjump; x=0;} + else if (x+framew>width) { + xclip = (x&1)<<1; + scrxjump = x&1; + xjump=((x+framew-width)>>1)+scrxjump; + framew = width-x;} + + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + /** ONLY 4-bit mode for time being **/ + for (scry = y; scry < y+h; scry+=1) { + if (scry>=height) return; + if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/ + for (scrx = x; scrx < framew+x-xclip; scrx+=2) { + uint8_t sourcepixel = *bitmap; + if (xclip) { + sourcepixel <<=4; + sourcepixel |= ((*(bitmap+1))>>4); + } + uint8_t targetpixel = *scrptr; + if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0x0F) | (sourcepixel & 0xF0); + if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F); + *scrptr = targetpixel; + bitmap++; + scrptr++; + } + if (xclip){ + if (framew&1) { + /**last pixel is odd pixel due to clipping & odd width*/ + uint8_t sourcepixel = *bitmap; + if ((sourcepixel&0x0F) != invisiblecolor) { + sourcepixel <<=4; + uint8_t targetpixel = *scrptr;// & 0x0F; + targetpixel |= sourcepixel; + *scrptr = targetpixel; + } + //scrptr++; + } + bitmap++; + scrptr++; + } + bitmap += xjump; // needed if x<0 clipping occurs + } else { /** ODD pixel starting line **/ + for (scrx = x; scrx < framew+x-xclip; scrx+=2) { + uint8_t sourcepixel = *bitmap; + uint8_t targetpixel = *scrptr; + // store higher nibble of source pixel in lower nibble of target + if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel >> 4 ); + *scrptr = targetpixel; + scrptr++; + targetpixel = *scrptr; + // store lower nibble of source pixel in higher nibble of target + if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel << 4); + *scrptr = targetpixel; + bitmap++; + } + bitmap+=xjump; + } + // increment the y jump in the scrptr + scrptr = scrptr + ((width - framew)>>1)+scrxjump; + } +} + + +void Display::drawBitmap(int16_t x, int16_t y, const uint8_t* bitmap) +{ + int16_t w = *bitmap; + int16_t h = *(bitmap + 1); + bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height + /** visibility check */ + if (y<-h || y>height) return; //invisible + if (x<-w || x>width) return; //invisible + /** 1 bpp mode */ + if (m_colordepth<2) { + int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + if (source & (0x80 >> bitNum)) { + drawPixel(x + i, y + j); + } + } + } + + return; + } + /** 2 bpp mode */ + if (m_colordepth<4) { + int16_t i, j, byteNum, bitNum, byteWidth = w >> 2; + for (i = 0; i < w; i++) { + byteNum = i / 4; + bitNum = (i % 4)<<1; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + uint8_t output = (source & (0xC0 >> bitNum)); + output >>= (6-bitNum); + if (output != invisiblecolor) { + setColor(output); + drawPixel(x + i, y + j); + } + } + } + + return; + } + /** 4bpp fast version */ + int16_t scrx,scry,xclip,xjump,scrxjump; + xclip=xjump=scrxjump=0; + /** y clipping */ + if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;} + else if (y+h>height) { h -=(y-height);} + /** x clipping */ + if (x<0) { xclip=(x&1)<<1; w+=x; xjump = ((-x)>>1); bitmap += xjump; x=0;} + else if (x+w>width) { + xclip = (x&1)<<1; + scrxjump = x&1; + xjump=((x+w-width)>>1)+scrxjump; + w = width-x;} + + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + /** ONLY 4-bit mode for time being **/ + for (scry = y; scry < y+h; scry+=1) { + if (scry>=height) return; + if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/ + for (scrx = x; scrx < w+x-xclip; scrx+=2) { + uint8_t sourcepixel = *bitmap; + if (xclip) { + sourcepixel <<=4; + sourcepixel |= ((*(bitmap+1))>>4); + } + uint8_t targetpixel = *scrptr; + if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0x0F) | (sourcepixel & 0xF0); + if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F); + *scrptr = targetpixel; + bitmap++; + scrptr++; + } + if (xclip){ + if (w&1) { + /**last pixel is odd pixel due to clipping & odd width*/ + uint8_t sourcepixel = *bitmap; + if ((sourcepixel&0x0F) != invisiblecolor) { + sourcepixel <<=4; + uint8_t targetpixel = *scrptr;// & 0x0F; + targetpixel |= sourcepixel; + *scrptr = targetpixel; + } + //scrptr++; + } + bitmap++; + scrptr++; + } + bitmap += xjump; // needed if x<0 clipping occurs + } else { /** ODD pixel starting line **/ + for (scrx = x; scrx < w+x-xclip; scrx+=2) { + uint8_t sourcepixel = *bitmap; + uint8_t targetpixel = *scrptr; + // store higher nibble of source pixel in lower nibble of target + if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel >> 4 ); + *scrptr = targetpixel; + scrptr++; + targetpixel = *scrptr; + // store lower nibble of source pixel in higher nibble of target + if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel << 4); + *scrptr = targetpixel; + bitmap++; + } + bitmap+=xjump; + } + // increment the y jump in the scrptr + scrptr = scrptr + ((width - w)>>1)+scrxjump; + } +} + +void Display::drawRleBitmap(int16_t x, int16_t y, const uint8_t* rlebitmap) +{ + // ONLY can copy 4-bit bitmap to 4-bit screen mode for time being + #if (POK_SCREENMODE != MODE_FAST_16COLOR) + return; + #endif + + int16_t w = *rlebitmap; + int16_t h = *(rlebitmap + 1); + rlebitmap = rlebitmap + 2; //add an offset to the pointer to start after the width and height + + // visibility check + if (y<-h || y>height) return; //invisible + if (x<-w || x>width) return; //invisible + + // Clipping is not supported + if ((x < 0) || (x+w > width) || (y < 0) || (y+h > height)) return; + + // Currently only support RLE bitmaps in 16 color mode. + if (m_colordepth != 4) // + return; + + // Go through each line. + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + bool is_endofbitmap = false; + for (int16_t scry = y; scry < y+h && !is_endofbitmap;) { + + // Process one line. Go through each pixel run and escape command in RLE data. + for (int16_t scrx = x;;) { + uint8_t rle_count = *rlebitmap++; + + if (rle_count == 0) { + + /** Escape or absolute mode */ + + uint8_t rle_escape_or_runsize = *rlebitmap++; + if ( rle_escape_or_runsize == RLE_ESC_EOL) { + // End of line. + break; + } + else if ( rle_escape_or_runsize == RLE_ESC_EOB) { + // End of bitmap. + is_endofbitmap = true; + break; + } + else if ( rle_escape_or_runsize == RLE_ESC_OFFSET) { + // Move position in target. + // TODO: not tested yet. + uint8_t xoffset = *rlebitmap++; + uint8_t yoffset = *rlebitmap++; + scrptr += (xoffset>1); + scrx += xoffset; + scrptr += yoffset*width; + scry += yoffset; + } + else { + + /** Absolute mode. Copy pixels from the source bitmap to the target screen. */ + + int16_t runsize = rle_escape_or_runsize; + uint8_t targetpixel = *scrptr; // initial value + uint8_t sourcepixel = *rlebitmap; // initial value + for( int16_t runx = 0; runx < runsize; ) { + if (scrx&0x1) { // screen pixel is in the low nibble + if (runx&0x1) { // bitmap pixel is in the low nibble + if ((sourcepixel&0x0F) != invisiblecolor) + targetpixel = (targetpixel&0xF0) | (sourcepixel&0x0F); // Copy low to low nibble. + rlebitmap++; + } + else // bitmap pixel is in the high nibble + if ((sourcepixel>>4) != invisiblecolor) + targetpixel = (targetpixel&0xF0) | (sourcepixel>>4); // Copy high to low nibble. + + // Copy the byte to the target. + *scrptr = targetpixel; + scrptr++; + } + else { // screen pixel is in the high nibble + targetpixel = *scrptr; + sourcepixel = *rlebitmap; + if (runx&0x1) { // bitmap pixel is sourcepixel = *rlebitmapin the low nibble + if ((sourcepixel&0x0F) != invisiblecolor ) + targetpixel = (targetpixel&0x0F) | ((sourcepixel<<4)&0xF0); // Copy low to high nibble. + rlebitmap++; // read the new source byte + } + else // bitmap pixel is in the high nibble + if ((sourcepixel>>4) != invisiblecolor ) + targetpixel = (targetpixel&0x0F) | (sourcepixel&0xF0); // Copy high to high nibble. + } + runx++; + scrx++; + } // end for + + // If this is odd target index, copy the byte to the target. + if (scrx&0x1) { + *scrptr = targetpixel; + scrptr++; + } + + // In absolute mode the source size is always padded to the word boundary. + if (runsize%4) { + int16_t padpixcount = 4 - (runsize%4); + rlebitmap += padpixcount>>1; // skip n padding bytes + } + } + } + else { + + /** Encoded mode. Duplicate one pixel pair to the all required pixels on the target screen */ + + int16_t runsize = rle_count; + uint8_t clonepixelpair = *rlebitmap++; + uint8_t targetpixel = *scrptr; // initial value + for( int16_t runx = 0; runx < runsize; ) { + if (scrx&0x1) { // screen pixel is in the low nibble + if (runx&0x1) { // bitmap pixel is in the low nibble + if ((clonepixelpair&0x0F) != invisiblecolor) + targetpixel = (targetpixel&0xF0) | (clonepixelpair&0x0F); // Copy low to low nibble. + } + else // bitmap pixel is in the high nibble + if ((clonepixelpair>>4) != invisiblecolor) + targetpixel = (targetpixel&0xF0) | (clonepixelpair>>4); // Copy high to low nibble. + + // Copy the byte to the target. + *scrptr = targetpixel; + scrptr++; + } + else { // screen pixel is in the high nibble + targetpixel = *scrptr; + if (runx&0x1) {// bitmap pixel is in the low nibble + if ((clonepixelpair&0x0F) != invisiblecolor ) + targetpixel = (targetpixel&0x0F) | ((clonepixelpair<<4)&0xF0); // Copy low to high nibble. + } + else // bitmap pixel is in the high nibble + if ((clonepixelpair>>4) != invisiblecolor ) + targetpixel = (targetpixel&0x0F) | (clonepixelpair&0xF0); // Copy high to high nibble. + } + runx++; + scrx++; + + } // end for + + // If this is odd target index, copy the byte to the target. + if (scrx&0x1) { + *scrptr = targetpixel; + scrptr++; + } + } // end if + } // end while + + // Increment the target screen pointer and index. + scrptr = scrptr + ((width - w)>>1); + scry++; + } // end for scry +} + +void Display::drawBitmapXFlipped(int16_t x, int16_t y, const uint8_t* bitmap) +{ + int16_t w = *bitmap; + int16_t h = *(bitmap + 1); + bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height + /** visibility check */ + if (y<-h || y>height) return; //invisible + if (x<-w || x>width) return; //invisible + /** 1 bpp mode */ + if (m_colordepth<2) { + int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3; + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + if (source & (0x80 >> bitNum)) { + drawPixel(x + w - i, y + j); + } + } + } + + return; + } + /** 2 bpp mode */ + if (m_colordepth<4) { + int16_t i, j, byteNum, bitNum, byteWidth = w >> 2; + for (i = 0; i < w; i++) { + byteNum = i / 4; + bitNum = (i % 4)<<1; + for (j = 0; j < h; j++) { + uint8_t source = *(bitmap + j * byteWidth + byteNum); + uint8_t output = (source & (0xC0 >> bitNum)); + output >>= (6-bitNum); + if (output != invisiblecolor) { + setColor(output); + drawPixel(x + i, y + j); + } + } + } + + return; + } + /** 4bpp fast version */ + int16_t scrx,scry,xclip,xjump,scrxjump; + xclip=xjump=scrxjump=0; + /** y clipping */ + if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;} + else if (y+h>height) { h -=(y-height);} + /** x clipping */ + bitmap += ((w>>1)-1); //inverted! + if (x<0) { + xclip=(x&1)<<1; + w+=x; + xjump = ((-x)>>1); + //bitmap += xjump; // do not clip left edge of source, as bitmap is inverted ! + x=0; + } + else if (x+w>width) { + xclip = (x&1)<<1; + scrxjump = x&1; + xjump=((x+w-width)>>1)+scrxjump; + w = width-x;} + + //uint8_t* scrptr = m_scrbuf + (y*(width>>1) + ((x+width)>>1)); + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + /** ONLY 4-bit mode for time being **/ + for (scry = y; scry < y+h; scry+=1) { + // for (scry = y; scry < y+2; scry+=1) { + if (scry>=height) return; + if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/ + //for (scrx = w+x-xclip-1; scrx >= x; scrx-=2) { + for (scrx = x; scrx < w+x-xclip; scrx+=2) { + uint8_t sourcepixel = *(bitmap); + if (xclip) { + sourcepixel <<=4; + sourcepixel |= ((*(bitmap-1))>>4);//inverted! + } + uint8_t targetpixel = *scrptr; + // NIBBLES ARE INVERTED BECAUSE PICTURE IS FLIPPED !!! + if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0xF0) | (sourcepixel>>4); + if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel<<4); + *scrptr = targetpixel; + bitmap--; + scrptr++; + } + bitmap += w; // w*2 >> 1 because inverted and because 2 pixels per byte!! + if (xclip){ + if (w&1) { + /**last pixel is odd pixel due to clipping & odd width*/ + uint8_t sourcepixel = *bitmap; + if ((sourcepixel&0x0F) != invisiblecolor) { + sourcepixel <<=4; + uint8_t targetpixel = *scrptr;// & 0x0F; + targetpixel |= sourcepixel; + *scrptr = targetpixel; + } + //scrptr++; + } + bitmap++; + scrptr++; + } + bitmap += xjump; // needed if x<0 clipping occurs + } else { /** ODD pixel starting line **/ + for (scrx = x; scrx < w+x-xclip; scrx+=2 ) { + uint8_t sourcepixel = *bitmap; + uint8_t targetpixel = *scrptr; + // inverted !!! store lower nibble of source pixel in lower nibble of target + if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F ); + *scrptr = targetpixel; + scrptr++; + targetpixel = *scrptr; + // inverted ! store higher nibble of source pixel in higher nibble of target + if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel & 0xF0); + *scrptr = targetpixel; + bitmap--; + } + bitmap += w; // w*2 >> 1 because inverted and because 2 pixels per byte!! + bitmap+=xjump; + } + // increment the y jump in the scrptr + scrptr = scrptr + ((width - w)>>1)+scrxjump; + } +} + +void Display::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t rotation, uint8_t flip) { +#if PROJ_GAMEBUINO == 0 + if (!flip) drawBitmap(x,y,bitmap); + else drawBitmapXFlipped(x,y,bitmap); +#else + if((rotation == NOROT) && (flip == NOFLIP)){ + drawBitmap(x,y,bitmap); //use the faster algorithm + return; + } + uint8_t w = bitmap[0]; + uint8_t h = bitmap[1]; + bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height + int8_t i, j, //coordinates in the raw bitmap + k, l, //coordinates in the rotated/flipped bitmap + byteNum, bitNum, byteWidth = (w + 7) >> 3; + + rotation %= 4; + + for (i = 0; i < w; i++) { + byteNum = i / 8; + bitNum = i % 8; + for (j = 0; j < h; j++) { + if (bitmap[j * byteWidth + byteNum] & (B10000000 >> bitNum)) { + switch (rotation) { + case NOROT: //no rotation + k = i; + l = j; + break; + case ROTCCW: //90� counter-clockwise + k = j; + l = w - i - 1; + break; + case ROT180: //180� + k = w - i - 1; + l = h - j - 1; + break; + case ROTCW: //90� clockwise + k = h - j - 1; + l = i; + break; + } + if (flip) { + flip %= 4; + if (flip & B00000001) { //horizontal flip + k = w - k; + } + if (flip & B00000010) { //vertical flip + l = h - l; + } + } + k += x; //place the bitmap on the screen + l += y; + drawPixel(k, l); + } + } + } +#endif //PROJ_GAMEBUINO + +} + +uint8_t* Display::getBuffer() { + return m_scrbuf; +} + +uint8_t Display::getBitmapPixel(const uint8_t* bitmap, uint16_t x, uint16_t y) { + uint16_t w = *bitmap; + uint8_t sourcebyte = bitmap[2+(y * ((w+7)>>3))+ (x>>3)]; + return sourcebyte & (0x80>>(x&7)); +} + +int Display::print_char(uint8_t x, uint8_t y, unsigned char c) { + c -= font[2]; + if (m_mode) return directChar(x,y,c); + return bufferChar(x,y,c); +} + +void Display::drawChar(int8_t x, int8_t y, unsigned char c, uint8_t size) { + print_char(x,y,c); + return; +} + + +bool Display::isDirectPrintingEnabled() { + return m_mode; +} + +void Display::enableDirectPrinting(uint8_t m) { + if (m) { + m_mode=true; + m_w = POK_LCD_W; + m_h = POK_LCD_H; + } else { + m_mode=false; + m_w = getWidth(); + m_h = getHeight(); + } +} + +void Display::write(uint8_t c) { + int charstep=0; + if(font[3]) { + // only caps in this font + if (c>=97) c-=32; + } + switch(c) { + case '\0': //null + break; + case '\n': //line feed + cursorX = 0; + inc_txtline(); + break; + case 8: //backspace + cursorX -= font[0]; + charstep=print_char(cursorX,cursorY,' '); + break; + case 13: //carriage return + cursorX = 0; + break; + case 14: //form feed new page(clear screen) + //clear_screen(); + break; + default: + if (cursorX >= (m_w - font[0])) { + cursorX = 0; + if (textWrap) inc_txtline(); + else return; // stop outputting text + charstep=print_char(cursorX,cursorY,c); + } + else + charstep=print_char(cursorX,cursorY,c); + if (c==' ' && adjustCharStep) charstep=(charstep>>1)+1; + cursorX += charstep; + } +} + +void Display::inc_txtline() { + if (cursorY > m_h - 2*font[1]) //= (height - (font[1]+1))) + #if SCROLL_TEXT > 0 + scroll(font[1] + adjustLineStep); + #else + cursorY = 0; + #endif + else + cursorY += font[1] + adjustLineStep; +} + +/* default implementation: may be overridden */ +void Display::write(const char *str) +{ + while (*str) + write(*str++); +} + +/* default implementation: may be overridden */ +void Display::write(const uint8_t *buffer, uint8_t size) +{ + while (size--) + write(*buffer++); +} + +void Display::print(const char str[]) +{ + write(str); +} + +void Display::print(char c, int base) +{ + print((long) c, base); +} + +void Display::print(unsigned char b, int base) +{ + print((unsigned long) b, base); +} + +void Display::print(int n, int base) +{ + print((long) n, base); +} + +void Display::print(unsigned int n, int base) +{ + print((unsigned long) n, base); +} + +void Display::print(long n, int base) +{ + if (base == 0) { + write(n); + } else if (base == 10) { + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); + } else { + printNumber(n, base); + } +} + +void Display::print(unsigned long n, int base) +{ + if (base == 0) write(n); + else printNumber(n, base); +} + +void Display::print(double n, int digits) +{ + printFloat(n, digits); +} + +void Display::println(void) +{ + print('\r'); + print('\n'); +} + +void Display::println(const char c[]) +{ + print(c); + println(); +} + +void Display::println(char c, int base) +{ + print(c, base); + println(); +} + +void Display::println(unsigned char b, int base) +{ + print(b, base); + println(); +} + +void Display::println(int n, int base) +{ + print(n, base); + println(); +} + +void Display::println(unsigned int n, int base) +{ + print(n, base); + println(); +} + +void Display::println(long n, int base) +{ + print(n, base); + println(); +} + +void Display::println(unsigned long n, int base) +{ + print(n, base); + println(); +} + +void Display::println(double n, int digits) +{ + print(n, digits); + println(); +} + +void Display::set_cursor(uint8_t x, uint8_t y) { + cursorX = x; + cursorY = y; +} + +void Display::print(uint8_t x, uint8_t y, const char str[]) { + cursorX = x; + cursorY = y; + write(str); + +} +void Display::print(uint8_t x, uint8_t y, char c, int base) { + cursorX = x; + cursorY = y; + print((long) c, base); +} +void Display::print(uint8_t x, uint8_t y, unsigned char b, int base) { + cursorX = x; + cursorY = y; + print((unsigned long) b, base); +} +void Display::print(uint8_t x, uint8_t y, int n, int base) { + cursorX = x; + cursorY = y; + print((long) n, base); +} +void Display::print(uint8_t x, uint8_t y, unsigned int n, int base) { + cursorX = x; + cursorY = y; + print((unsigned long) n, base); +} +void Display::print(uint8_t x, uint8_t y, long n, int base) { + cursorX = x; + cursorY = y; + print(n,base); +} +void Display::print(uint8_t x, uint8_t y, unsigned long n, int base) { + cursorX = x; + cursorY = y; + print(n,base); +} +void Display::print(uint8_t x, uint8_t y, double n, int digits) { + cursorX = x; + cursorY = y; + print(n,digits); +} + +void Display::println(uint8_t x, uint8_t y, const char c[]) +{ + cursorX = x; + cursorY = y; + print(c); + println(); +} + +void Display::println(uint8_t x, uint8_t y, char c, int base) +{ + cursorX = x; + cursorY = y; + print(c, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, unsigned char b, int base) +{ + cursorX = x; + cursorY = y; + print(b, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, int n, int base) +{ + cursorX = x; + cursorY = y; + print(n, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, unsigned int n, int base) +{ + cursorX = x; + cursorY = y; + print(n, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, long n, int base) +{ + cursorX = x; + cursorY = y; + print(n, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, unsigned long n, int base) +{ + cursorX = x; + cursorY = y; + print(n, base); + println(); +} + +void Display::println(uint8_t x, uint8_t y, double n, int digits) +{ + cursorX = x; + cursorY = y; + print(n, digits); + println(); +} + +void Display::printNumber(unsigned long n, uint8_t base) +{ + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + + if (n == 0) { + print('0'); + return; + } + + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + + for (; i > 0; i--) + print((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); +} + +void Display::printFloat(double number, uint8_t digits) +{ + // Handle negative numbers + if (number < 0.0) + { + print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i<digits; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + print(int_part); + + // Print the decimal point, but only if there are digits beyond + if (digits > 0) + print("."); + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; + } +} + +void Display::draw4BitColumn(int16_t x, int16_t y, uint8_t h, uint8_t* bitmap) +{ + int8_t scry; + uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1)); + + /** ONLY 4-bit mode for time being **/ + + if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/ + for (scry = y; scry < h+y; scry++) { + uint8_t sourcepixel = *bitmap; + uint8_t targetpixel = *scrptr; + targetpixel = (targetpixel&0x0F) | (sourcepixel << 4); + *scrptr = targetpixel; + bitmap++; + scrptr+=55; + } + } else { /** ODD pixel starting line **/ + for (scry = y; scry < h+y; scry++) { + uint8_t sourcepixel = *bitmap; + uint8_t targetpixel = *scrptr; + // store source pixel in lower nibble of target + targetpixel = (targetpixel & 0xF0) | (sourcepixel); + *scrptr = targetpixel; + scrptr+=55; + bitmap++; + } + } +} + +void Display::lcdRefresh(unsigned char* scr) { + +#if POK_SCREENMODE == MODE_GAMEBOY + lcdRefreshModeGBC(scr, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_HI_4COLOR + lcdRefreshMode1(scr, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_FAST_16COLOR + lcdRefreshMode2(scr, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_GAMEBUINO_16COLOR + lcdRefreshGB(scr, paletteptr); +#endif + +#if POK_SCREENMODE == MODE_ARDUBOY_16COLOR + lcdRefreshAB(scr, paletteptr); +#endif + +} + +void Display::setFrameBufferTo(uint8_t* sb) { + m_scrbuf = sb; +}; + +void Display::setTileBufferTo(uint8_t* tb) { + m_tilebuf = tb; +}; + +void Display::loadTileset(const uint8_t* ts) { + m_tileset = (uint8_t*) ts; +}; + +void Display::setTile(uint16_t i, uint8_t t) { + if (!m_tilebuf) return; + m_tilebuf[i]=t; +}; + + +/** Eof */ + + +