PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PokittoDisplay.cpp Source File

PokittoDisplay.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*!
00003     @file     PokittoDisplay.cpp
00004     @author   Jonne Valola
00005 
00006     @section LICENSE
00007 
00008     Software License Agreement (BSD License)
00009 
00010     Copyright (c) 2016, Jonne Valola
00011     All rights reserved.
00012 
00013     Redistribution and use in source and binary forms, with or without
00014     modification, are permitted provided that the following conditions are met:
00015     1. Redistributions of source code must retain the above copyright
00016     notice, this list of conditions and the following disclaimer.
00017     2. Redistributions in binary form must reproduce the above copyright
00018     notice, this list of conditions and the following disclaimer in the
00019     documentation and/or other materials provided with the distribution.
00020     3. Neither the name of the copyright holders nor the
00021     names of its contributors may be used to endorse or promote products
00022     derived from this software without specific prior written permission.
00023 
00024     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
00025     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00028     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00033     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 */
00035 /**************************************************************************/
00036 
00037 
00038 /* THE SEGMENT BELOW PERTAINS TO CIRCLE DRAWING FUNCTIONS ONLY
00039 *
00040 This is the core graphics library for all our displays, providing a common
00041 set of graphics primitives (points, lines, circles, etc.).  It needs to be
00042 paired with a hardware-specific library for each display device we carry
00043 (to handle the lower-level functions).
00044 Adafruit invests time and resources providing this open source code, please
00045 support Adafruit & open-source hardware by purchasing products from Adafruit!
00046 Copyright (c) 2013 Adafruit Industries.  All rights reserved.
00047 Redistribution and use in source and binary forms, with or without
00048 modification, are permitted provided that the following conditions are met:
00049 - Redistributions of source code must retain the above copyright notice,
00050   this list of conditions and the following disclaimer.
00051 - Redistributions in binary form must reproduce the above copyright notice,
00052   this list of conditions and the following disclaimer in the documentation
00053   and/or other materials provided with the distribution.
00054 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00055 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00056 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00057 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00058 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00059 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00060 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00061 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00062 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00063 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00064 POSSIBILITY OF SUCH DAMAGE.
00065 */
00066 
00067 #include "PokittoDisplay.h "
00068 #include "Pokitto_settings.h "
00069 #include "GBcompatibility.h"
00070 #include "PokittoCore.h "
00071 #include "PokittoSound.h "
00072 #include <stdio.h>
00073 #include <string.h>
00074 #ifdef DISABLEAVRMIN
00075 #include <algorithm>
00076 using std::min;
00077 using std::max;
00078 #endif // DISABLEAVRMIN
00079 
00080 #ifndef POK_SIM
00081 #include "HWLCD.h "
00082 #else
00083 #include "SimLCD.h"
00084 #endif
00085 
00086 extern "C" void CheckStack();
00087 extern char _ebss[];  // In map file
00088 extern char _vStackTop[];  // In map file
00089 
00090 Pokitto::Core core;
00091 Pokitto::Sound _pdsound;
00092 
00093 using namespace Pokitto;
00094 
00095 uint8_t* Display::m_scrbuf;
00096 uint8_t* Display::m_tileset;
00097 uint8_t* Display::m_tilebuf;
00098 uint8_t* Display::m_tilecolorbuf;
00099 uint8_t Display::m_mode, Display::m_colordepth;
00100 uint8_t Display::palOffset;
00101 SpriteInfo Display::m_sprites[SPRITE_COUNT];
00102 uint8_t Display::fontSize=1;
00103 int16_t Display::cursorX,Display::cursorY;
00104 uint16_t Display::m_w,Display::m_h;
00105 uint8_t Display::fontWidth, Display::fontHeight;
00106 bool Display::textWrap=true;
00107 
00108 uint8_t Display::persistence = 0;
00109 uint16_t Display::color = 1;
00110 uint16_t Display::bgcolor = 0;
00111 uint16_t Display::invisiblecolor = 17;
00112 uint16_t Display::directcolor=0xFFFF;
00113 uint16_t Display::directbgcolor=0x0;
00114 bool Display::directtextrotated=false;
00115 int16_t Display::clipX = 0;
00116 int16_t Display::clipY = 0;
00117 int16_t Display::clipW = LCDWIDTH;
00118 int16_t Display::clipH = LCDHEIGHT;
00119 
00120 uint16_t* Display::paletteptr;
00121 uint16_t Display::palette[PALETTE_SIZE];
00122 const unsigned char* Display::font;
00123 int8_t Display::adjustCharStep = 1;
00124 int8_t Display::adjustLineStep = 1;
00125 bool Display::fixedWidthFont = false, Display::flipFontVertical = false;
00126 
00127 /** drawing canvas **/
00128 //uint8_t* Display::canvas; // points to the active buffer. if null, draw direct to screen
00129 
00130 /** screenbuffer **/
00131 uint8_t Display::bpp = POK_COLORDEPTH;
00132 #ifndef POK_TILEDMODE
00133 #if (POK_SCREENMODE == MODE_HI_MONOCHROME)
00134     uint8_t Display::width = POK_LCD_W;
00135     uint8_t Display::height = POK_LCD_H;
00136     uint8_t Display::screenbuffer[((POK_LCD_H+1)*POK_LCD_W)*POK_COLORDEPTH/8]; // maximum resolution
00137 #elif (POK_SCREENMODE == MODE_HI_4COLOR)
00138     uint8_t Display::width = POK_LCD_W;
00139     uint8_t Display::height = POK_LCD_H;
00140     uint8_t __attribute__((section (".bss"))) __attribute__ ((aligned)) Display::screenbuffer[((POK_LCD_H)*POK_LCD_W)/4]; // maximum resolution
00141 #elif (POK_SCREENMODE == MODE_FAST_16COLOR)
00142     uint8_t Display::width = POK_LCD_W/2;
00143     uint8_t Display::height = POK_LCD_H/2;
00144     uint8_t Display::screenbuffer[(((POK_LCD_H/2)+1)*POK_LCD_W/2)*POK_COLORDEPTH/8]; // half resolution
00145 #elif (POK_SCREENMODE == MODE_HI_16COLOR)
00146     uint8_t Display::width = POK_LCD_W;
00147     uint8_t Display::height = POK_LCD_H;
00148     uint8_t Display::screenbuffer[POK_LCD_H*POK_LCD_W/2]; // 4 bits per pixel
00149 #elif (POK_SCREENMODE == MODE_LAMENES)
00150     uint8_t Display::width = 128;
00151     uint8_t Display::height = 120;
00152     uint8_t Display::screenbuffer[((121)*128)*POK_COLORDEPTH/8]; // half resolution
00153 #elif (POK_SCREENMODE == MODE_GAMEBOY)
00154     uint8_t Display::width = 160;
00155     uint8_t Display::height = 144;
00156     uint8_t Display::screenbuffer[160*144/4];
00157 #elif (POK_SCREENMODE == MODE14)
00158     uint8_t Display::width = 220;
00159     uint8_t Display::height = 176;
00160     uint8_t Display::screenbuffer[14520];
00161 #elif (POK_SCREENMODE == MODE13)
00162     uint8_t Display::width = 110;
00163     uint8_t Display::height = 88;
00164     uint8_t Display::screenbuffer[110*88]; // 8bit 110x88
00165 #elif (POK_SCREENMODE == MIXMODE)
00166     uint8_t Display::width = 110;
00167     uint8_t Display::height = 88;
00168     uint8_t Display::screenbuffer[110*88]; // 8bit 110x88 or 4bit 110x176
00169     uint8_t Display::scanType[88]; // scanline bit depth indicator
00170 #elif (POK_SCREENMODE == MODE64)
00171     uint8_t Display::width = 110;
00172     uint8_t Display::height = 176;
00173     uint8_t __attribute__ ((aligned)) Display::screenbuffer[110*176]; // 8bit 110x176
00174 #elif (POK_SCREENMODE == MODE15)
00175     uint8_t Display::width = 220;
00176     uint8_t Display::height = 176;
00177     uint8_t __attribute__ ((aligned)) Display::screenbuffer[0x4BA0];
00178 #else
00179     uint8_t Display::width = 84;
00180     uint8_t Display::height = 48;
00181     uint8_t Display::screenbuffer[128*64]; // not needed because Gamebuino and Arduboy have their own buffer
00182 #endif
00183 #else //Tiledmode
00184 #if (POK_SCREENMODE == MODE_TILED_1BIT)
00185     uint8_t Display::width = POK_LCD_W;
00186     uint8_t Display::height = POK_LCD_H;
00187     uint8_t Display::screenbuffer[0];
00188 #else
00189     uint8_t Display::width = POK_LCD_W;
00190     uint8_t Display::height = POK_LCD_H;
00191     uint8_t Display::screenbuffer[0];
00192 #endif
00193 #endif //tiledmode
00194 
00195 // RLE decoding
00196 #define RLE_ESC_EOL 0
00197 #define RLE_ESC_EOB 1
00198 #define RLE_ESC_OFFSET 2
00199 
00200 Display::Display() {
00201     m_scrbuf = screenbuffer;
00202     setDefaultPalette();
00203     m_mode = 1; // direct printing on by default
00204     m_w = POK_LCD_W;
00205     m_h = POK_LCD_H;
00206     setFont(DEFAULT_FONT);
00207     invisiblecolor=17;
00208     bgcolor=0;
00209     if (POK_COLORDEPTH) m_colordepth = POK_COLORDEPTH;
00210     else m_colordepth = 4;
00211     #if POK_GAMEBUINO_SUPPORT
00212     setColorDepth(1);
00213     #endif // POK_GAMEBUINO_SUPPORT
00214 
00215     // Reset sprites
00216     m_tilecolorbuf = NULL; //!!HV
00217     for (uint8_t s = 0; s < SPRITE_COUNT; s++) m_sprites[s].bitmapData = NULL;
00218 }
00219 
00220 uint16_t Display::getWidth() {
00221     return width;
00222 }
00223 
00224 uint8_t Display::getNumberOfColors() {
00225     return 1<<POK_COLORDEPTH;
00226 }
00227 
00228 uint16_t Display::getHeight() {
00229     return height;
00230 }
00231 
00232 uint8_t Display::getColorDepth() {
00233     return m_colordepth;
00234 }
00235 
00236 void Display::setColorDepth(uint8_t v) {
00237     if (v > POK_COLORDEPTH) v=POK_COLORDEPTH;
00238     m_colordepth = v;
00239 }
00240 
00241 void Display::clearLCD() {
00242     lcdFillSurface(0);
00243     setCursor(0,0); // old basic computer style
00244 }
00245 
00246 void Display::fillLCD(uint16_t c) {
00247     lcdFillSurface(c);
00248 }
00249 
00250 void Display::directPixel(int16_t x, int16_t y, uint16_t color) {
00251     if ((invisiblecolor < PALETTE_SIZE) && (invisiblecolor < 16) && (color == palette[invisiblecolor])) return;
00252     lcdPixel(x,y,color);
00253 }
00254 
00255 void Display::directTile(int16_t x, int16_t y, int16_t x2, int16_t y2, uint16_t* gfx) {
00256     lcdTile(x,y,x2,y2,gfx);
00257 }
00258 
00259 void Display::directRectangle(int16_t x, int16_t y,int16_t x2, int16_t y2, uint16_t color) {
00260     lcdRectangle(x,y,x2,y2,color);
00261 }
00262 
00263 void Display::begin() {
00264     lcdInit();
00265 }
00266 
00267 void Display::setCursor(int16_t x,int16_t y) {
00268     cursorX = x;
00269     cursorY = y;
00270 }
00271 
00272 /**
00273  * Update the display.
00274  * The update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, the
00275  * x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
00276  * Note: The update rect is currently used for 220x176, 4 colors, screen mode only.
00277  * @param useDirectMode True, if only direct screen drawing is used. False, if the screen buffer is drawn. Note: If sprites are enabled, they are drawn in both modes.
00278  * @param updRectX The update rect.
00279  * @param updRectY The update rect.
00280  * @param updRectW The update rect.
00281  * @param updRectH The update rect.
00282  */
00283 void Display::update(bool useDirectDrawMode, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH) {
00284 
00285     #if POK_SCREENMODE == MODE_HI_4COLOR
00286     // If there is one or more sprites, use sprite enabled drawing.
00287     if (m_sprites[0].bitmapData != NULL)
00288         lcdRefreshMode1Spr(m_scrbuf, updRectX, updRectY, updRectW, updRectH, paletteptr, m_sprites, useDirectDrawMode);
00289     else if (!useDirectDrawMode)
00290         lcdRefreshMode1(m_scrbuf, updRectX, updRectY, updRectW, updRectH, paletteptr);
00291     #endif
00292 
00293     // For the screen modes that do not support sprites, return if the direct draw mode is used.
00294     if (! useDirectDrawMode) {
00295         #if POK_SCREENMODE == MODE13
00296         lcdRefreshMode13(m_scrbuf, paletteptr, palOffset);
00297         #endif
00298 
00299         #if POK_SCREENMODE == MIXMODE
00300         lcdRefreshMixMode(m_scrbuf, paletteptr, scanType);
00301         #endif
00302 
00303         #if POK_SCREENMODE == MODE64
00304         lcdRefreshMode64(m_scrbuf, paletteptr);
00305         #endif
00306 
00307         #if POK_SCREENMODE == MODE_GAMEBOY
00308         lcdRefreshModeGBC(m_scrbuf, paletteptr);
00309         #endif
00310 
00311         #if POK_SCREENMODE == MODE_HI_16COLOR
00312         lcdRefreshMode3(m_scrbuf, paletteptr);
00313         #endif
00314 
00315         #if POK_SCREENMODE == MODE_FAST_16COLOR
00316         lcdRefreshMode2(m_scrbuf, paletteptr);
00317         #endif
00318 
00319         #if POK_SCREENMODE == MODE_GAMEBUINO_16COLOR
00320         lcdRefreshGB(m_scrbuf, paletteptr);
00321         #endif
00322 
00323         #if POK_SCREENMODE == MODE_ARDUBOY_16COLOR
00324         lcdRefreshAB(m_scrbuf, paletteptr);
00325         #endif
00326 
00327         #if POK_SCREENMODE == MODE14
00328         lcdRefreshMode14(m_scrbuf, paletteptr);
00329         #endif
00330 
00331         #if POK_SCREENMODE == MODE15
00332         lcdRefreshMode15(paletteptr, m_scrbuf);
00333         #endif
00334 
00335         #if POK_SCREENMODE == MODE_TILED_1BIT
00336         lcdRefreshT1(m_tilebuf, m_tilecolorbuf, m_tileset, paletteptr);
00337         #endif
00338     }
00339 
00340     if (!persistence) clear();
00341 
00342     /** draw volume bar if visible **/
00343     #if POK_SHOW_VOLUME > 0
00344     if (core.volbar_visible) {
00345             core.drawvolbar(4,20,_pdsound.getVolume(),true);
00346             core.volbar_visible--;
00347     }
00348     #endif // POK_SHOW_VOLUME
00349 
00350     /** draw FPS if visible **/
00351     #ifdef PROJ_SHOW_FPS_COUNTER
00352 
00353     if(core.fps_counter_updated) {
00354 
00355         // Store current state
00356         bool temp = isDirectPrintingEnabled();
00357         uint16_t oldcol = directcolor;
00358         uint16_t oldinvisiblecolor = invisiblecolor;
00359         uint16_t oldbgcol = directbgcolor;
00360         bool olddirecttextrotated = directtextrotated;
00361         int8_t oldadjustCharStep = adjustCharStep;
00362         const unsigned char * oldFont = font;
00363 
00364         // Print FPS
00365         char str[16];
00366         sprintf(str,"FPS:%d ", (int)core.fps_counter);
00367         directcolor = COLOR_WHITE;
00368         invisiblecolor = COLOR_BLACK;
00369         directbgcolor = 0x0001; // Cannot be black as that is transparent color
00370     directtextrotated = false;
00371         adjustCharStep = 0;
00372         setFont(fontC64);
00373         enableDirectPrinting(true);
00374         print(0,0, str);
00375 
00376         // Restore state
00377         enableDirectPrinting(temp);
00378         directcolor = oldcol;
00379         invisiblecolor =  oldinvisiblecolor;
00380         directbgcolor = oldbgcol;
00381         directtextrotated = olddirecttextrotated;
00382         adjustCharStep = oldadjustCharStep;
00383         setFont(oldFont);
00384 
00385         core.fps_counter_updated = false;
00386     }
00387     #endif
00388 }
00389 
00390 void Display::directBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t depth, uint8_t scale) {
00391     uint8_t w = *bitmap;
00392     uint8_t h = *(bitmap + 1);
00393     bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
00394     int16_t i, j;
00395     int8_t byteNum, bitNum, byteWidth = (w + 7) >> 3;
00396 
00397     if (depth == 1) {
00398         for (i = 0; i < w; i++) {
00399             byteNum = i / 8;
00400             bitNum = i % 8;
00401             for (j = 0; j < h; j++) {
00402                 if (*(bitmap + j * byteWidth + byteNum) & (0x80 >> bitNum)) { //0x80 = B10000000
00403                     if (scale==1) directPixel(x + i, y + j,directcolor);
00404                     else {
00405                         directPixel(x + i + i, y + j + j,directcolor);
00406                         directPixel(x + 1 + i + i, y + j + j,directcolor);
00407                         directPixel(x + i + i, y + j + j + 1,directcolor);
00408                         directPixel(x + i + i + 1 , y + j + j + 1,directcolor);
00409                     }
00410                 }
00411             }
00412         }
00413     } else if (depth == 4) {
00414         for (j = 0; j < h; j+=1) {
00415             for (i = 0; i < w; i+=2) {
00416                 uint16_t col = paletteptr[*bitmap>>4]; //higher nibble
00417                 if (scale==2) {
00418                         directPixel(x + (i<<1), y + (j<<1),col);
00419                         directPixel(x + (i<<1) + 1, y + (j<<1),col);
00420                         directPixel(x + (i<<1) + 1, y + (j<<1) + 1,col);
00421                         directPixel(x + (i<<1), y + (j<<1) + 1,col);
00422                 } else directPixel(x + i, y + j,col);
00423                 col = paletteptr[*bitmap&0xF]; // lower nibble
00424                 if (scale==2) {
00425                         directPixel(x + (i<<1) + 2, y + (j<<1),col);
00426                         directPixel(x + (i<<1) + 1 + 2, y + (j<<1),col);
00427                         directPixel(x + (i<<1) + 1 + 2, y + (j<<1) + 1,col);
00428                         directPixel(x + (i<<1) + 2 , y + (j<<1) + 1,col);
00429                 } else directPixel(x + i + 1, y + j,col);
00430                 bitmap++;
00431             }
00432         }
00433     }
00434 
00435 }
00436 
00437 int Display::directChar(int16_t x, int16_t y, uint16_t index){
00438     const uint8_t* bitmap = font;
00439     uint8_t w = *bitmap;
00440     uint8_t h = *(bitmap + 1);
00441     uint8_t hbytes=0, xtra=1;
00442     if (h==8 || h==16) xtra=0; //don't add if exactly on byte limit
00443     hbytes=(h>>3)+xtra; //GLCD fonts are arranged w+1 times h/8 bytes
00444     //bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !)
00445     bitmap = bitmap + 4 + index * (w * hbytes + 1); //add an offset to the pointer (fonts !)
00446     //int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
00447     int8_t i, j, numBytes;
00448     numBytes = *bitmap++; //first byte of char is the width in bytes
00449     // GLCD fonts are arranged LSB = topmost pixel of char, so its easy to just shift through the column
00450     uint16_t bitcolumn; //16 bits for 2x8 bit high characters
00451 
00452     for (i = 0; i < numBytes; i++) {
00453             bitcolumn = *bitmap++;
00454             if (hbytes == 2) bitcolumn |= (*bitmap++)<<8; // add second byte for 16 bit high fonts
00455             for (j = 0; j < h; j++) {
00456                 if (bitcolumn&0x1) {
00457                     if (fontSize==2) {
00458                         directPixel(x + (i<<1)  , y + (j<<1),directcolor);
00459                         directPixel(x + (i<<1)+1, y + (j<<1),directcolor);
00460                         directPixel(x + (i<<1)  , y + (j<<1)+1,directcolor);
00461                         directPixel(x + (i<<1)+1, y + (j<<1)+1,directcolor);
00462                     } else {
00463                         if(directtextrotated) directPixel(y + h - j - 1, x + i,directcolor);
00464                         else directPixel(x + i, y + j,directcolor);
00465                     }
00466 
00467                 } else if (directbgcolor != invisiblecolor) {
00468                     if (fontSize==2) {
00469                         directPixel(x + (i<<1)  , y + (j<<1),directbgcolor);
00470                         directPixel(x + (i<<1)+1, y + (j<<1),directbgcolor);
00471                         directPixel(x + (i<<1)  , y + (j<<1)+1,directbgcolor);
00472                         directPixel(x + (i<<1)+1, y + (j<<1)+1,directbgcolor);
00473                     } else {
00474                         if(directtextrotated) directPixel(y + h - j - 1, x + i,directbgcolor);
00475                         else directPixel(x + i, y + j,directbgcolor);
00476                     }
00477                 }
00478                 bitcolumn>>=1;
00479             }
00480     }
00481     return (numBytes+adjustCharStep)*fontSize; // for character stepping
00482 }
00483 
00484 int Display::bufferChar(int16_t x, int16_t y, uint16_t index){
00485     const uint8_t* bitmap = font;
00486     uint8_t w = *bitmap;
00487     uint8_t h = *(bitmap + 1);
00488     uint8_t hbytes=0, xtra=1;
00489     if (h==8 || h==16) xtra=0; //don't add if exactly on byte limit
00490     hbytes=(h>>3)+xtra; //GLCD fonts are arranged w+1 times h/8 bytes
00491     //bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !)
00492     bitmap = bitmap + 4 + index * (w * hbytes + 1); //add an offset to the pointer (fonts !)
00493     //int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
00494     int8_t i, j, numBytes;
00495     numBytes = *bitmap++; //first byte of char is the width in bytes
00496     // GLCD fonts are arranged LSB = topmost pixel of char, so its easy to just shift through the column
00497     uint16_t bitcolumn; //16 bits for 2x8 bit high characters
00498 
00499     void (*drawPixelFG)(int16_t,int16_t, uint8_t) = &Display::drawPixelNOP;
00500     void (*drawPixelBG)(int16_t,int16_t, uint8_t) = &Display::drawPixelNOP;
00501     if( x>=0 && y >= 0 && x+w<width && y+h<height ){
00502     if( color != invisiblecolor )
00503         drawPixelFG = &Display::drawPixelRaw;
00504     if( bgcolor != invisiblecolor )
00505         drawPixelBG = &Display::drawPixelRaw;
00506     }else{
00507     if( color != invisiblecolor )
00508         drawPixelFG = &Display::drawPixel;
00509     if( bgcolor != invisiblecolor )
00510         drawPixelBG = &Display::drawPixel;
00511     }
00512 
00513     void (*drawPixel[])(int16_t,int16_t, uint8_t) = {drawPixelBG, drawPixelFG};
00514     uint8_t colors[] = {bgcolor, color};
00515 
00516 #if PROJ_ARDUBOY > 0
00517 #else
00518     if( fontSize != 2 ){
00519 #endif
00520 
00521     for (i = 0; i < numBytes; i++) {
00522     bitcolumn = *bitmap++;
00523     if (hbytes == 2) bitcolumn |= (*bitmap++)<<8; // add second byte for 16 bit high fonts
00524     for (j = 0; j <= h; j++) { // was j<=h
00525         uint8_t c = colors[ bitcolumn & 1 ];
00526 
00527 #if PROJ_ARDUBOY > 0
00528         drawPixel[ bitcolumn&1 ](x, y + 7 - j,c);
00529 #elif PROJ_SUPPORT_FONTROTATION > 0
00530        // if font flipping & rotation is allowed - do not slow down old programs!
00531        if (flipFontVertical) {
00532            drawPixel[ bitcolumn&1 ](x, y + h - j,c);
00533        } else {
00534            drawPixel[ bitcolumn&1 ](x, y + j,c);
00535        }
00536 #else
00537        // "Normal" case
00538         drawPixel[ bitcolumn&1 ](x, y + j,c);
00539 #endif // PROJ_ARDUBOY
00540         bitcolumn>>=1;
00541 
00542     }
00543 #if PROJ_SUPPORT_FONTROTATION > 0
00544     if (flipFontVertical) x--;
00545     else x++;
00546 #else
00547     x++;
00548 #endif
00549     }
00550 
00551 #if PROJ_SUPPORT_FONTROTATION > 0
00552     if (flipFontVertical) return -numBytes-adjustCharStep;
00553     else return numBytes+adjustCharStep; // for character stepping
00554 #else
00555     return numBytes+adjustCharStep;
00556 #endif
00557 
00558 
00559 #if PROJ_ARDUBOY > 0
00560 #else
00561     }else{
00562 
00563     for (i = 0; i < numBytes; i++) {
00564         bitcolumn = *bitmap++;
00565         if (hbytes == 2) bitcolumn |= (*bitmap++)<<8; // add second byte for 16 bit high fonts
00566         for (j = 0; j <= h; j++) { // was j<=h
00567         uint8_t c = colors[ bitcolumn & 1 ];
00568 
00569         drawPixel[ bitcolumn&1 ](x + (i<<1)  , y + (j<<1), c);
00570         drawPixel[ bitcolumn&1 ](x + (i<<1)+1, y + (j<<1), c);
00571         drawPixel[ bitcolumn&1 ](x + (i<<1)  , y + (j<<1)+1, c);
00572         drawPixel[ bitcolumn&1 ](x + (i<<1)+1, y + (j<<1)+1, c);
00573         bitcolumn>>=1;
00574 
00575         }
00576     }
00577 
00578     return (numBytes+adjustCharStep)<<1;
00579 
00580     }
00581 #endif // PROJ_ARDUBOY
00582 
00583 }
00584 
00585 void Display::clear() {
00586 
00587     uint8_t c=0;
00588     c = bgcolor & (PALETTE_SIZE-1) ; //don't let palette go out of bounds
00589     if (bpp==1 && bgcolor) c=0xFF; // bgcolor !=0, set all pixels
00590     else if (bpp==2) {
00591         c = bgcolor & 0x3;
00592         c = c | (c << 2);
00593         c = c | (c << 4);
00594     } else if (bpp==3){
00595         uint16_t j = POK_BITFRAME;
00596         if (bgcolor & 0x1) memset((void*)m_scrbuf,0xFF,j);// R
00597         else memset((void*)m_scrbuf,0x00,j);// R
00598         if ((bgcolor>>1) & 0x1) memset((void*)m_scrbuf+POK_BITFRAME,0xFF,j);// G
00599         else memset((void*)m_scrbuf+POK_BITFRAME,0x00,j);// G
00600         if ((bgcolor>>2) & 0x1) memset((void*)m_scrbuf+POK_BITFRAME*2,0xFF,j);// B
00601         else memset((void*)m_scrbuf+POK_BITFRAME*2,0x00,j);// B
00602         setCursor(0,0);
00603         return;
00604     } else if (bpp==4) {
00605         c = (c & 0x0F) | (c << 4);
00606     }
00607     uint16_t j = sizeof(screenbuffer);
00608     memset((void*)m_scrbuf,c,j);
00609 
00610     setCursor(0,0);
00611 
00612 }
00613 
00614 void Display::scroll(int16_t pixelrows) {
00615     uint16_t index = 0, index2=0,oc;
00616     if (pixelrows==0) return;
00617     if (pixelrows >= height) pixelrows=height-1;
00618     if (bpp == 4) index2 = pixelrows*width/2;
00619     else if (bpp == 2) index2 = pixelrows*width/4;
00620     else return;
00621     oc = color;
00622     color = bgcolor;
00623     if (pixelrows>0) {
00624     for (uint16_t y=0;y<height-pixelrows;y++) {
00625             for (uint16_t x=0;x<(width/8)*bpp;x++) screenbuffer[index++]=screenbuffer[index2++];
00626     }
00627     fillRect(0,cursorY,width,height);
00628     } else {
00629     for (uint16_t y=pixelrows;y<height;y++) {
00630             for (uint16_t x=0;x<(width*bpp)/8;x++) screenbuffer[index2++]=screenbuffer[index++];
00631     }
00632     fillRect(0,0,width,pixelrows);
00633     }
00634     color=oc;
00635 }
00636 
00637 void Display::fillScreen(uint16_t c) {
00638     c = c & (PALETTE_SIZE-1) ; //don't let palette go out of bounds
00639     if (bpp==1 && c) c=0xFF; // set all pixels
00640     else if (bpp==2) {
00641         c = c & 0x3;
00642         c = c | (c << 2);
00643         c = c | (c << 4);
00644     } else {
00645         c = (c & 0x0F) | (c << 4);
00646     }
00647     memset((void*)m_scrbuf,c,sizeof(screenbuffer));
00648 }
00649 
00650 void Display::setDefaultPalette() {
00651     #if PICOPALETTE
00652         loadRGBPalette(palettePico);
00653     #else
00654         loadRGBPalette(POK_DEFAULT_PALETTE);
00655     #endif //PICOPALETTE
00656 }
00657 
00658 void Display::setColor(uint8_t c) {
00659     color = c & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit
00660 }
00661 
00662 void Display::setColor(uint8_t c,uint8_t bgc){
00663     color = c & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit
00664     bgcolor = bgc & ((1<<POK_COLORDEPTH)-1); // cut out colors that go above palette limit
00665 }
00666 
00667 void Display::setInvisibleColor(uint16_t c){
00668     invisiblecolor = c; // invisible color can have values beyond 255 for identification purposes
00669 }
00670 
00671 uint8_t Display::getColor() {
00672     return color;
00673 }
00674 
00675 uint8_t Display::getBgColor() {
00676     return bgcolor;
00677 }
00678 
00679 uint16_t Display::getInvisibleColor() {
00680     return invisiblecolor;
00681 }
00682 
00683 void Display::setClipRect(int16_t x, int16_t y, int16_t w, int16_t h) {
00684     clipX = x; clipY = y; clipW = w; clipH = h;
00685 }
00686 
00687 void Display::drawPixelNOP(int16_t x,int16_t y, uint8_t col) {
00688 }
00689 
00690 void Display::drawPixelRaw(int16_t x,int16_t y, uint8_t col) {
00691     #if POK_COLORDEPTH == 8
00692         m_scrbuf[x+width*y] = col;
00693     #endif
00694 
00695     #if POK_GAMEBUINO_SUPPORT >0
00696 
00697     uint8_t c = col;
00698     uint8_t ct = col;
00699 
00700     uint16_t bitptr=0;
00701     for (uint8_t cbit=0;cbit<POK_COLORDEPTH;cbit++) {
00702     c = ct & 1; // take the lowest bit of the color index number
00703     if(c == 0){ //white - or actually "Clear bit"
00704         m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] &= ~_BV(y % 8);
00705     } else { //black - or actually "Set bit"
00706         m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] |= _BV(y % 8);
00707     }
00708     ct >>=1; // shift to get next bit
00709     bitptr += POK_BITFRAME; // move one screen worth of buffer forward to get to the next color bit
00710     } // POK_COLOURDEPTH
00711 
00712     #else
00713     #if POK_COLORDEPTH == 1
00714         if (col) {m_scrbuf[(y >> 3) * width + x] |= (0x80 >> (y & 7)); return;}
00715         m_scrbuf[(y >> 3) * width + x] &= ~(0x80 >> (y & 7));
00716     #elif POK_COLORDEPTH == 2
00717         if (col) {
00718                 col &= 3;
00719         }
00720         uint16_t i = y*(width>>2) + (x>>2);
00721         uint8_t pixel = m_scrbuf[i];
00722         uint8_t column = x&0x03;
00723         if (column==3) pixel = (pixel&0xFC)|(col); // bits 0-1
00724         else if (column==2) pixel = (pixel&0xF3)|(col<<2); // bits 2-3
00725         else if (column==1) pixel = (pixel&0xCF)|(col<<4); // bits 4-5
00726         else pixel = (pixel&0x3F)|(col<<6); // bits 6-7
00727         m_scrbuf[i] = pixel;
00728     #elif POK_COLORDEPTH == 3
00729     uint8_t c = col;
00730     uint8_t ct = col;
00731 
00732     uint16_t bitptr=0;
00733     for (uint8_t cbit=0;cbit<POK_COLORDEPTH;cbit++) {
00734     c = ct & 1; // take the lowest bit of the color index number
00735     if(c == 0){ //white - or actually "Clear bit"
00736         m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] &= ~_BV(y % 8);
00737     } else { //black - or actually "Set bit"
00738         m_scrbuf[x + (y / 8) * LCDWIDTH + bitptr] |= _BV(y % 8);
00739     }
00740     ct >>=1; // shift to get next bit
00741     bitptr += POK_BITFRAME; // move one screen worth of buffer forward to get to the next color bit
00742     } // POK_COLOURDEPTH
00743     #elif POK_COLORDEPTH == 4
00744     uint16_t i = y*(width>>1) + (x>>1);
00745     uint8_t pixel = m_scrbuf[i];
00746     if (x&1) pixel = (pixel&0xF0)|(col);
00747     else pixel = (pixel&0x0F) | (col<<4);
00748     m_scrbuf[i] = pixel;
00749     #endif // POK_COLORDEPTH
00750     #endif // POK_GAMEBUINO_SUPPORT
00751 }
00752 
00753 void Display::drawPixel(int16_t x,int16_t y, uint8_t col) {
00754     if (col==invisiblecolor) return; // do not draw transparent pixels
00755     if ((uint16_t)x >= width || (uint16_t)y >= height) return;
00756     col &= (PALETTE_SIZE-1);
00757     drawPixelRaw( x, y, col );
00758 }
00759 
00760 void Display::drawPixel(int16_t x,int16_t y) {
00761     if ((uint16_t)x >= width || (uint16_t)y >= height) return;
00762     drawPixelRaw( x, y, color );
00763 }
00764 
00765 uint8_t Display::getPixel(int16_t x,int16_t y) {
00766     if ((uint16_t)x >= width || (uint16_t)y >= height) return 0;
00767     #if POK_COLORDEPTH == 8
00768     uint16_t i = y*width+x;
00769     return m_scrbuf[i];
00770     #endif // POK_COLORDEPTH
00771 
00772     #if POK_GAMEBUINO_SUPPORT
00773     uint8_t color=0; //jonne
00774     for (uint8_t cbit=0; cbit<POK_COLORDEPTH;cbit++) {
00775         color |= (m_scrbuf[x + (y / 8) * LCDWIDTH+POK_BITFRAME*cbit] >> (y % 8)) & 0x1 ; //jonne - added +504*cbit
00776     }
00777     return color;
00778     #else
00779     /** not gamebuino */
00780     #if POK_COLORDEPTH == 1
00781         return (m_scrbuf[(y >> 3) * width + x] & (0x80 >> (y & 7))) ? 1:0;
00782     #elif POK_COLORDEPTH == 2
00783         uint16_t i = y*(width>>2) + (x>>2);
00784         uint8_t pixel = m_scrbuf[i];
00785         uint8_t column = x&0x03;
00786         if (column==0) return pixel & 0x03; // bits 0-1
00787         else if (column==1) return (pixel & 0x0C)>>2; // bits 2-3
00788         else if (column==2) return (pixel & 0x30)>>4; // bits 4-5
00789         else return pixel>>6;; // bits 6-7
00790     #elif POK_COLORDEPTH == 3
00791     #elif POK_COLORDEPTH == 4
00792     uint16_t i = y*(width>>1) + (x>>1);
00793     uint8_t pixel = m_scrbuf[i];
00794     if (x&1) return pixel & 0x0F;
00795     else return pixel>>4;
00796     #endif // POK_COLORDEPTH
00797     #endif // POK_GAMEBUINO_SUPPORT
00798 }
00799 
00800 void Display::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
00801     if ((uint16_t)x0 >= width || (uint16_t)y0 >= height || (uint16_t)x1 >= width || (uint16_t)y1 >= height ) {
00802         if (clipLine (&x0,&y0,&x1,&y1)==0) return; // line out of bounds
00803     }
00804     if (x0 == x1)
00805         drawColumn(x0,y0,y1);
00806     else if (y0 == y1)
00807         drawRow(x0,x1,y0);
00808     else {
00809         int e;
00810         signed int dx,dy,j, temp;
00811         signed char s1,s2, xchange;
00812         signed int x,y;
00813 
00814         x = x0;
00815         y = y0;
00816 
00817         //take absolute value
00818         if (x1 < x0) {
00819             dx = x0 - x1;
00820             s1 = -1;
00821         }
00822         else if (x1 == x0) {
00823             dx = 0;
00824             s1 = 0;
00825         }
00826         else {
00827             dx = x1 - x0;
00828             s1 = 1;
00829         }
00830 
00831         if (y1 < y0) {
00832             dy = y0 - y1;
00833             s2 = -1;
00834         }
00835         else if (y1 == y0) {
00836             dy = 0;
00837             s2 = 0;
00838         }
00839         else {
00840             dy = y1 - y0;
00841             s2 = 1;
00842         }
00843 
00844         xchange = 0;
00845 
00846         if (dy>dx) {
00847             temp = dx;
00848             dx = dy;
00849             dy = temp;
00850             xchange = 1;
00851         }
00852 
00853         e = ((int)dy<<1) - dx;
00854 
00855         for (j=0; j<=dx; j++) {
00856             drawPixel(x,y);
00857 
00858             if (e>=0) {
00859                 if (xchange==1) x = x + s1;
00860                 else y = y + s2;
00861                 e = e - ((int)dx<<1);
00862             }
00863             if (xchange==1)
00864                 y = y + s2;
00865             else
00866                 x = x + s1;
00867             e = e + ((int)dy<<1);
00868         }
00869     }
00870 }
00871 
00872 uint8_t Display::clipLine(int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1){
00873     // Check X bounds
00874     if (*x1 < *x0) {
00875         //std::swap (*x1,*x0); // swap so that we dont have to check x1 also
00876         swapWT(int16_t*, x1, x0);
00877         //std::swap (*y1,*y0); // y needs to be swaaped also
00878         swapWT(int16_t*, y1, y0);
00879     }
00880 
00881     if (*x0 >= width) return 0; // whole line is out of bounds
00882 
00883     // Clip against X0 = 0
00884     if (*x0 < 0) {
00885         if (*x1 < 0) return 0; // nothing visible
00886         int32_t dx = (*x1 - *x0);
00887         int32_t dy = ((*y1 - *y0) << 16); // 16.16 fixed point calculation trick
00888         int32_t m = dy/dx;
00889         *y0 = *y0 + ((m*-*x0) >> 16); // get y0 at boundary
00890         *x0 = 0;
00891     }
00892 
00893     // Clip against x1 >= width
00894     if (*x1 >= width) {
00895         int32_t dx = (*x1 - *x0);
00896         int32_t dy = ((*y1 - *y0) << 16); // 16.16 fixed point calculation trick
00897         int32_t m = dy / dx;
00898         *y1 = *y1 + ((m * ((width - 1) - *x1)) >> 16); // get y0 at boundary
00899         *x1 = width-1;
00900     }
00901 
00902     // Check Y bounds
00903     if (*y1 < *y0) {
00904         //std::swap (*x1,*x0); // swap so that we dont have to check x1 also
00905         swapWT(int16_t*, x1, x0);
00906         //std::swap (*y1,*y0); // y needs to be swaaped also
00907         swapWT(int16_t*, y1, y0);
00908     }
00909 
00910     if (*y0 >= height) return 0; // whole line is out of bounds
00911 
00912     if (*y0 < 0) {
00913         if (*y1 < 0) return 0; // nothing visible
00914         int32_t dx = (*x1 - *x0) << 16;
00915         int32_t dy = (*y1 - *y0); // 16.16 fixed point calculation trick
00916         int32_t m = dx / dy;
00917         *x0 = *x0 + ((m * -(*y0)) >> 16); // get x0 at boundary
00918         *y0 = 0;
00919     }
00920 
00921     // Clip against y1 >= height
00922     if (*y1 >= height) {
00923         int32_t dx = (*x1 - *x0) << 16;
00924         int32_t dy = (*y1 - *y0); // 16.16 fixed point calculation trick
00925         int32_t m = dx / dy;
00926         *x1 = *x1 + ((m * ((height - 1) - *y1)) >> 16); // get y0 at boundary
00927         *y1 = height-1;
00928     }
00929     return 1; // clipped succesfully
00930 }
00931 
00932 void Display::map1BitColumn(int16_t x, int16_t sy, int16_t ey, const uint8_t* bitmap, uint16_t column){
00933     if ((uint16_t)sy>=height && (uint16_t)ey>=height) return; //completely out of bounds
00934     if ((uint16_t)x>=width) return; //completely out of bounds
00935     if (sy>ey) {
00936             int y=sy;
00937             sy=ey;
00938             ey=y; // swap around so that x0 is less than x1
00939     }
00940     uint16_t bmw,bmh;
00941     float texelstep, texelindex;
00942     bmw = *(bitmap);
00943     bmh = *(bitmap+1);
00944     if (column>bmw-1) column=bmw-1;
00945     bitmap += 2;
00946     bitmap += column;
00947     texelstep = (float)bmh/((float)ey-(float)sy);
00948     texelindex = 0;
00949     for (int y=sy; y <= ey; y++, texelindex += texelstep) {
00950         uint8_t texel;
00951         uint8_t currbyte, bit;
00952         currbyte = texelindex / 8;
00953         bit = 7-((uint16_t) texelindex & 0x7);
00954         texel=*(bitmap+currbyte*bmw);
00955         if (texel & (1<<bit)) drawPixel(x,y);
00956         else if (bgcolor != invisiblecolor) drawPixel(x,y,bgcolor);
00957     }
00958 };
00959 
00960 void Display::drawColumn(int16_t x, int16_t sy, int16_t ey){
00961     if ((uint16_t)sy>=height && (uint16_t)ey>=height) return; //completely out of bounds
00962     if ((uint16_t)x>=width) return; //completely out of bounds
00963     if (sy>ey) {
00964             int y=sy;
00965             sy=ey;
00966             ey=y; // swap around so that x0 is less than x1
00967     }
00968     for (int y=sy; y <= ey; y++) {
00969         drawPixel(x,y);
00970     }
00971 }
00972 
00973 void Display::drawRow(int16_t x0, int16_t x1, int16_t y){
00974     if ((uint16_t)x0>=width && (uint16_t)x1>=width) return; //completely out of bounds
00975     if ((uint16_t)y>=height) return; //completely out of bounds
00976 
00977     if (x0>x1) {
00978             int x=x0;
00979             x0=x1;
00980             x1=x; // swap around so that x0 is less than x1
00981     }
00982     for (int x=x0; x <= x1; x++) {
00983         drawPixel(x,y);
00984     }
00985 }
00986 
00987 void Display::drawFastVLine(int16_t x, int16_t y, int16_t h){
00988     if (h<0) {y += h; h = -h;}
00989     drawColumn(x,y,y+h);
00990 }
00991 
00992 void Display::drawFastHLine(int16_t x, int16_t y, int16_t w){
00993     if (w<0) {x += w; w = -w;}
00994     drawRow(x,x+w-1,y);
00995 }
00996 
00997 void Display::drawRectangle(int16_t x0, int16_t y0, int16_t w, int16_t h) {
00998     drawColumn(x0,y0,y0+h);
00999     drawColumn(x0+w,y0,y0+h);
01000     drawRow(x0,x0+w,y0);
01001     drawRow(x0,x0+w,y0+h);
01002 }
01003 
01004 void Display::fillRectangle(int16_t x0,int16_t y0, int16_t w, int16_t h){
01005     int16_t x,y,x1,y1;
01006     x1=x0+w;y1=y0+h;
01007     if ((x0<0 && x1<0) || (x0>=width && x1 >=width)) return; //completely out of bounds
01008     if ((y0<0 && y1<0) || (y0>=height && y1 >=height)) return; //completely out of bounds
01009     if (x0>x1) {x=x1;x1=x0;}
01010     else x=x0;
01011     if (y0>y1) {y=y1;y1=y0;}
01012     else y=y0;
01013     if (x<0) x=0;
01014     if (y<0) y=0;
01015     for (;x<x1;x++) drawColumn(x,y,y1);
01016 }
01017 
01018 void Display::fillRect(int16_t x, int16_t y, int16_t w, int16_t h) {
01019     fillRectangle(x,y,w,h);
01020 }
01021 
01022 void Display::drawRect(int16_t x, int16_t y, int16_t w, int16_t h) {
01023     drawRectangle(x,y,w,h);
01024 }
01025 
01026 void Display::drawCircle(int16_t x0, int16_t y0, int16_t r) {
01027     int16_t f = 1 - r;
01028     int16_t ddF_x = 1;
01029     int16_t ddF_y = -2 * r;
01030     int16_t x = 0;
01031     int16_t y = r;
01032 
01033     drawPixel(x0, y0 + r);
01034     drawPixel(x0, y0 - r);
01035     drawPixel(x0 + r, y0);
01036     drawPixel(x0 - r, y0);
01037 
01038     while (x < y) {
01039         if (f >= 0) {
01040 
01041             y--;
01042             ddF_y += 2;
01043             f += ddF_y;
01044         }
01045         x++;
01046         ddF_x += 2;
01047         f += ddF_x;
01048 
01049         drawPixel(x0 + x, y0 + y);
01050         drawPixel(x0 - x, y0 + y);
01051         drawPixel(x0 + x, y0 - y);
01052         drawPixel(x0 - x, y0 - y);
01053         drawPixel(x0 + y, y0 + x);
01054         drawPixel(x0 - y, y0 + x);
01055         drawPixel(x0 + y, y0 - x);
01056         drawPixel(x0 - y, y0 - x);
01057 
01058     }
01059 }
01060 
01061 void Display::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint16_t cornername) {
01062     int16_t f = 1 - r;
01063     int16_t ddF_x = 1;
01064     int16_t ddF_y = -2 * r;
01065     int16_t x = 0;
01066     int16_t y = r;
01067 
01068     while (x < y) {
01069         if (f >= 0) {
01070             y--;
01071             ddF_y += 2;
01072             f += ddF_y;
01073         }
01074         x++;
01075         ddF_x += 2;
01076         f += ddF_x;
01077         if (cornername & 0x4) {
01078             drawPixel(x0 + x, y0 + y);
01079             drawPixel(x0 + y, y0 + x);
01080         }
01081         if (cornername & 0x2) {
01082             drawPixel(x0 + x, y0 - y);
01083             drawPixel(x0 + y, y0 - x);
01084         }
01085         if (cornername & 0x8) {
01086             drawPixel(x0 - y, y0 + x);
01087             drawPixel(x0 - x, y0 + y);
01088         }
01089         if (cornername & 0x1) {
01090 
01091             drawPixel(x0 - y, y0 - x);
01092             drawPixel(x0 - x, y0 - y);
01093         }
01094     }
01095 }
01096 
01097 void Display::fillCircle(int16_t x0, int16_t y0, int16_t r) {
01098     drawFastVLine(x0, y0 - r, 2 * r );
01099     fillCircleHelper(x0, y0, r, 3, 0);
01100 }
01101 
01102 void Display::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint16_t cornername, int16_t delta) {
01103     int16_t f = 1 - r;
01104     int16_t ddF_x = 1;
01105     int16_t ddF_y = -2 * r;
01106     int16_t x = 0;
01107     int16_t y = r;
01108 
01109     while (x < y) {
01110         if (f >= 0) {
01111             y--;
01112             ddF_y += 2;
01113             f += ddF_y;
01114         }
01115         x++;
01116         ddF_x += 2;
01117         f += ddF_x;
01118 
01119         if (cornername & 0x1) {
01120             drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta-1); //added -1 here, jonne
01121             drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta-1); //added -1 here, jonne
01122         }
01123         if (cornername & 0x2) {
01124 
01125             drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta-1); //added -1 here, jonne
01126             drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta-1); //added -1 here, jonne
01127         }
01128     }
01129 }
01130 
01131 void Display::drawRoundRect(int16_t x, int16_t y, int16_t w,int16_t h, int16_t r) {
01132     if (r<2) {drawRectangle(x,y,w,h);return;}
01133     // smarter version
01134     drawFastHLine(x + r, y, w - 2 * r); // Top
01135     drawFastHLine(x + r, y + h - 1, w - 2 * r); // Bottom
01136     drawFastVLine(x, y + r, h - 2 * r); // Left
01137     drawFastVLine(x + w - 1, y + r, h - 2 * r); // Right
01138     // draw four corners
01139     drawCircleHelper(x + r, y + r, r, 1);
01140     drawCircleHelper(x + w - r - 1, y + r, r, 2);
01141     drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4);
01142     drawCircleHelper(x + r, y + h - r - 1, r, 8);
01143 }
01144 
01145 void Display::fillRoundRect(int16_t x, int16_t y, int16_t w,int16_t h, int16_t r) {
01146     if (r<2) {fillRectangle(x,y,w,h);return;}
01147     fillRectangle(x + r, y, w - 2 * r, h-1);
01148     // draw four corners
01149     fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1);
01150     fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1);
01151 }
01152 
01153 void Display::drawTriangle(int16_t x0, int16_t y0,
01154         int16_t x1, int16_t y1,
01155         int16_t x2, int16_t y2) {
01156     drawLine(x0, y0, x1, y1);
01157     drawLine(x1, y1, x2, y2);
01158     drawLine(x2, y2, x0, y0);
01159 }
01160 
01161 void Display::fillTriangle(int16_t x0, int16_t y0,
01162         int16_t x1, int16_t y1,
01163         int16_t x2, int16_t y2) {
01164     int16_t a, b, y, last;
01165 
01166     // Sort coordinates by Y order (y2 >= y1 >= y0)
01167     if (y0 > y1) {
01168         swapWT(int16_t,y0, y1);
01169         swapWT(int16_t,x0, x1);
01170     }
01171     if (y1 > y2) {
01172         swapWT(int16_t,y2, y1);
01173         swapWT(int16_t,x2, x1);
01174     }
01175     if (y0 > y1) {
01176         swapWT(int16_t,y0, y1);
01177         swapWT(int16_t,x0, x1);
01178     }
01179 
01180     if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
01181         a = b = x0;
01182         if (x1 < a) a = x1;
01183         else if (x1 > b) b = x1;
01184         if (x2 < a) a = x2;
01185         else if (x2 > b) b = x2;
01186         drawFastHLine(a, y0, b - a + 1);
01187         return;
01188     }
01189 
01190     int16_t
01191     dx01 = x1 - x0,
01192             dy01 = y1 - y0,
01193             dx02 = x2 - x0,
01194             dy02 = y2 - y0,
01195             dx12 = x2 - x1,
01196             dy12 = y2 - y1,
01197             sa = 0,
01198             sb = 0;
01199 
01200     // For upper part of triangle, find scanline crossings for segments
01201     // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
01202     // is included here (and second loop will be skipped, avoiding a /0
01203     // error there), otherwise scanline y1 is skipped here and handled
01204     // in the second loop...which also avoids a /0 error here if y0=y1
01205     // (flat-topped triangle).
01206     if (y1 == y2) last = y1; // Include y1 scanline
01207     else last = y1 - 1; // Skip it
01208 
01209     for (y = y0; y <= last; y++) {
01210         a = x0 + sa / dy01;
01211         b = x0 + sb / dy02;
01212         sa += dx01;
01213         sb += dx02;
01214         /* longhand:
01215         a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
01216         b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
01217          */
01218         if (a > b) swapWT(int16_t,a, b);
01219         drawFastHLine(a, y, b - a + 1);
01220     }
01221 
01222     // For lower part of triangle, find scanline crossings for segments
01223     // 0-2 and 1-2.  This loop is skipped if y1=y2.
01224     sa = dx12 * (y - y1);
01225     sb = dx02 * (y - y0);
01226     for (; y <= y2; y++) {
01227         a = x1 + sa / dy12;
01228         b = x0 + sb / dy02;
01229         sa += dx12;
01230         sb += dx02;
01231 
01232         if (a > b) swapWT(int16_t,a, b);
01233         drawFastHLine(a, y, b - a + 1);
01234     }
01235 }
01236 
01237 void Display::setFont(const unsigned char * f) {
01238     font = f;
01239     fontWidth = *(font)+1;
01240     fontHeight = *(font + 1)+1;
01241 }
01242 
01243 void Display::drawMonoBitmap(int16_t x, int16_t y, const uint8_t* bitmap, uint8_t index) {
01244     uint8_t w = *bitmap;
01245     uint8_t h = *(bitmap + 1);
01246     uint8_t xtra=0;
01247     if (w&0x7) xtra=1;
01248     bitmap = bitmap + 3 + index * h * ((w>>3)+xtra); //add an offset to the pointer (fonts !)
01249     #if POK_GAMEBUINO_SUPPORT > 0
01250     int8_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
01251     for (i = 0; i < w; i++) {
01252         byteNum = i / 8;
01253         bitNum = i % 8;
01254         for (j = 0; j < h; j++) {
01255             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01256             if (source & (0x80 >> bitNum)) {
01257                 drawPixel(x + i, y + j);
01258             }
01259         }
01260     }
01261     #else
01262     /** not gamebuino */
01263     int8_t scrx,scry;
01264     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
01265     int8_t bitptr;
01266     for (scry = y; scry < y+h; scry+=1) {
01267             if ((x&1)==0) { /** EVEN pixel starting line**/
01268                 for (scrx = x, bitptr=7; scrx < w+x; scrx+=2) {
01269                     uint8_t targetpixel = *scrptr;
01270                     if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF) | color<<4; // upper nibble
01271                     else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF) | bgcolor<<4; // upper nibble
01272                     bitptr--;
01273                     if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF0) | color; // lower nibble
01274                     else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF0) | bgcolor; // lower nibble
01275                     bitptr--;
01276                     if (bitptr<0) { bitptr = 7; bitmap++; }
01277                     *scrptr = targetpixel;
01278                     scrptr++;
01279                 }
01280             } else { /** ODD pixel starting line **/
01281                 for (scrx = x, bitptr=7; scrx < w+x; scrx+=2) {
01282                     uint8_t targetpixel = *scrptr;
01283                     // store higher nibble of source pixel in lower nibble of target
01284                     if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF0) | color; // lower nibble
01285                     else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF0) | bgcolor; // lower nibble
01286                     *scrptr = targetpixel; // store
01287                     bitptr--;scrptr++;targetpixel = *scrptr;
01288                     // store lower nibble of source pixel in higher nibble of target
01289                     if (*bitmap & (1<<bitptr)) targetpixel = (targetpixel & 0xF) | color<<4; // higher nibble
01290                     else if (bgcolor != invisiblecolor) targetpixel = (targetpixel & 0xF) | bgcolor<<4; // higher nibble
01291                     *scrptr = targetpixel; // store
01292                     bitptr--; // do not increment scrptr here !
01293                 }
01294             }
01295             if (bitptr!=7) bitmap++; // force skip to next line
01296             // increment the y jump in the scrptr
01297             scrptr = scrptr + ((width - w)>>1);
01298     }
01299     #endif // POK_GAMEBUINO_SUPPORT
01300 }
01301 
01302 
01303 void Display::drawBitmap(int16_t x, int16_t y, const uint8_t* bitmap, uint8_t frame)
01304 {
01305     int16_t w = *bitmap;
01306     int16_t h = *(bitmap + 1);
01307     uint8_t framew = *(bitmap+2);
01308     bitmap = bitmap + 3; //add an offset to the pointer to start after the width and height
01309     /** visibility check */
01310     if (y<-h || y>height) return; //invisible
01311     if (x<-framew || x>width) return;  //invisible
01312     /** 1 bpp mode */
01313     if (m_colordepth<2) {
01314     int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
01315     for (i = 0; i < w; i++) {
01316         byteNum = i / 8;
01317         bitNum = i % 8;
01318         for (j = 0; j < h; j++) {
01319             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01320             if (source & (0x80 >> bitNum)) {
01321                 drawPixel(x + i, y + j);
01322             }
01323         }
01324     }
01325 
01326     return;
01327     }
01328     /** 2 bpp mode */
01329     if (m_colordepth<4) {
01330     int16_t i, j, byteNum, bitNum, byteWidth = w >> 2;
01331     for (i = 0; i < w; i++) {
01332         byteNum = i / 4;
01333         bitNum = (i % 4)<<1;
01334         for (j = 0; j < h; j++) {
01335             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01336             uint8_t output = (source & (0xC0 >> bitNum));
01337             output >>= (6-bitNum);
01338             if (output != invisiblecolor) {
01339                 setColor(output);
01340                 drawPixel(x + i, y + j);
01341             }
01342         }
01343     }
01344 
01345     return;
01346     }
01347     /** 4bpp fast version */
01348     int16_t scrx,scry,xclip,xjump,scrxjump;
01349     xclip=xjump=scrxjump=0;
01350     bitmap += (framew*frame)>>1;
01351     /** y clipping */
01352     if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;}
01353     else if (y+h>height) { h -=(y-height);}
01354     /** x clipping */
01355     xjump = (w-framew)>>1;
01356     if (x<0) { xclip=(x&1)<<1; framew+=x; xjump = ((-x)>>1); bitmap += xjump; x=0;}
01357     else if (x+framew>width) {
01358             xclip = (x&1)<<1;
01359             scrxjump = x&1;
01360             xjump=((x+framew-width)>>1)+scrxjump;
01361             framew = width-x;}
01362 
01363     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
01364     /** ONLY 4-bit mode for time being **/
01365     for (scry = y; scry < y+h; scry+=1) {
01366             if (scry>=height) return;
01367             if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/
01368                 for (scrx = x; scrx < framew+x-xclip; scrx+=2) {
01369                     uint8_t sourcepixel = *bitmap;
01370                     if (xclip) {
01371                             sourcepixel <<=4;
01372                             sourcepixel |= ((*(bitmap+1))>>4);
01373                     }
01374                     uint8_t targetpixel = *scrptr;
01375                     if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0x0F) | (sourcepixel & 0xF0);
01376                     if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F);
01377                     *scrptr = targetpixel;
01378                     bitmap++;
01379                     scrptr++;
01380                 }
01381                 if (xclip){
01382                     if (framew&1) {
01383                         /**last pixel is odd pixel due to clipping & odd width*/
01384                         uint8_t sourcepixel = *bitmap;
01385                         if ((sourcepixel&0x0F) != invisiblecolor) {
01386                             sourcepixel <<=4;
01387                             uint8_t targetpixel = *scrptr;// & 0x0F;
01388                             targetpixel |= sourcepixel;
01389                             *scrptr = targetpixel;
01390                         }
01391                         //scrptr++;
01392                     }
01393                     bitmap++;
01394                     scrptr++;
01395                 }
01396                 bitmap += xjump; // needed if x<0 clipping occurs
01397             } else { /** ODD pixel starting line **/
01398                 for (scrx = x; scrx < framew+x-xclip; scrx+=2) {
01399                     uint8_t sourcepixel = *bitmap;
01400                     uint8_t targetpixel = *scrptr;
01401                     // store higher nibble of source pixel in lower nibble of target
01402                     if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel >> 4 );
01403                     *scrptr = targetpixel;
01404                     scrptr++;
01405                     targetpixel = *scrptr;
01406                     // store lower nibble of source pixel in higher nibble of target
01407                     if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel << 4);
01408                     *scrptr = targetpixel;
01409                     bitmap++;
01410                 }
01411                 bitmap+=xjump;
01412             }
01413             // increment the y jump in the scrptr
01414             scrptr = scrptr + ((width - framew)>>1)+scrxjump;
01415     }
01416 }
01417 
01418 
01419 void Display::drawBitmap(int16_t x, int16_t y, const uint8_t* bitmap)
01420 {
01421     int16_t w = *bitmap;
01422     int16_t h = *(bitmap + 1);
01423     bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
01424     drawBitmapData(x, y, w, h, bitmap);
01425 }
01426 
01427 void Display::drawBitmapData(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t* bitmap) {
01428     /** visibility check */
01429     if (y<-h || y>height) return; //invisible
01430     if (x<-w || x>width) return;  //invisible
01431     /** 1 bpp mode */
01432     if (m_colordepth<2) {
01433     int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
01434     for (i = 0; i < w; i++) {
01435         byteNum = i / 8;
01436         bitNum = i % 8;
01437         for (j = 0; j < h; j++) {
01438             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01439             if (source & (0x80 >> bitNum)) {
01440                 drawPixel(x + i, y + j);
01441             }
01442         }
01443     }
01444 
01445     return;
01446     }
01447     /** 2 bpp mode */
01448     else if (m_colordepth==2) {
01449         if(clipH > 0) {
01450 
01451             // Clip
01452             int16_t x1 = max(x, clipX);
01453             int16_t x2 = min(x + w, clipX + clipW);
01454             int16_t bmupdateX = x1 - x;
01455             int16_t bmupdateX2 = x2 - x;
01456             int16_t y1 = max(y, clipY);
01457             int16_t y2 = min(y + h, clipY + clipH);
01458             int16_t bmupdateY = y1 - y;
01459             int16_t bmupdateY2 = y2 - y;
01460 
01461             int16_t i, j, byteNum, bitNum, byteWidth = w >> 2;
01462             for (i = bmupdateX; i < bmupdateX2; i++) {
01463                 byteNum = i / 4;
01464                 bitNum = (i % 4)<<1;
01465                 for (j = bmupdateY; j < bmupdateY2; j++) {
01466                     uint8_t source = *(bitmap + (j * byteWidth) + byteNum);
01467                     uint8_t output = (source & (0xC0 >> bitNum));
01468                     output >>= (6-bitNum);
01469                     if (output != invisiblecolor) {
01470                         setColor(output);
01471                         drawPixel(x + i, y + j);
01472                     }
01473                 }
01474             }
01475         }
01476         else {
01477             int16_t i, j, byteNum, bitNum, byteWidth = w >> 2;
01478             for (i = 0; i < w; i++) {
01479                 byteNum = i / 4;
01480                 bitNum = (i % 4)<<1;
01481                 for (j = 0; j < h; j++) {
01482                     uint8_t source = *(bitmap + (j * byteWidth) + byteNum);
01483                     uint8_t output = (source & (0xC0 >> bitNum));
01484                     output >>= (6-bitNum);
01485                     if (output != invisiblecolor) {
01486                         setColor(output);
01487                         drawPixel(x + i, y + j);
01488                     }
01489                 }
01490             }
01491         }
01492         return;
01493     }
01494 
01495     /** 3 bpp mode */
01496     else if (m_colordepth==3) {
01497         int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
01498         int16_t bitFrame = w * h / 8;
01499         for (i = 0; i < w; i++) {
01500         byteNum = i / 8;
01501         bitNum = i % 8;
01502 
01503         uint8_t bitcount=0;
01504         for (j = 0; j <= h/8; j++) {
01505             uint8_t r_val = *(bitmap + j * byteWidth + byteNum);
01506             uint8_t g_val = *(bitmap + bitFrame + j * byteWidth + byteNum);
01507             uint8_t b_val = *(bitmap + (bitFrame<<1) + j * byteWidth + byteNum);
01508             for (bitcount=0; bitcount<8; bitcount++) {
01509                 uint8_t col = (r_val&0x1) | ((g_val&0x1)<<1) | ((b_val&0x1)<<2);
01510                 r_val >>= 1; g_val >>= 1; b_val >>= 1;
01511                 drawPixel(x + i, y + j+bitcount,col);
01512             }
01513             }
01514         }
01515 
01516     return;
01517     }
01518 
01519 
01520     /** 4bpp fast version */
01521     else if (m_colordepth==4) {
01522 
01523     /** 4bpp fast version */
01524     int16_t scrx,scry,xjump,scrxjump;
01525     int16_t xclip;
01526     xclip=xjump=scrxjump=0;
01527     /** y clipping */
01528     if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;}
01529     else if (y+h>height) { h -=(y-height);}
01530     /** x clipping */
01531     if (x<0) { xclip=(x&1)<<1; w+=x; xjump = ((-x)>>1); bitmap += xjump; x=0;}
01532     else if (x+w>width) {
01533             xclip = (x&1)<<1;
01534             scrxjump = x&1;
01535             xjump=((x+w-width)>>1)+scrxjump;
01536             w = width-x;}
01537 
01538     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
01539     /** ONLY 4-bit mode for time being **/
01540     for (scry = y; scry < y+h; scry+=1) {
01541             if (scry>=height) return;
01542             if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/
01543                 for (scrx = x; scrx < w+x-xclip; scrx+=2) {
01544                     uint8_t sourcepixel = *bitmap;
01545                     if (xclip) {
01546                             sourcepixel <<=4;
01547                             sourcepixel |= ((*(bitmap+1))>>4);
01548                     }
01549                     uint8_t targetpixel = *scrptr;
01550                     if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0x0F) | (sourcepixel & 0xF0);
01551                     if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F);
01552                     *scrptr = targetpixel;
01553                     bitmap++;
01554                     scrptr++;
01555                 }
01556                 if (xclip){
01557                     if (w&1) {
01558                         /**last pixel is odd pixel due to clipping & odd width*/
01559                         uint8_t sourcepixel = *bitmap;
01560                         if ((sourcepixel&0x0F) != invisiblecolor) {
01561                             sourcepixel <<=4;
01562                             volatile uint8_t targetpixel = *scrptr;// & 0x0F;
01563                             targetpixel &= 0xF; //clear upper nibble
01564                             targetpixel |= sourcepixel; //now OR it
01565                             *scrptr = targetpixel;
01566                         }
01567                         //scrptr++;
01568                     }
01569                     bitmap++;
01570                     scrptr++;
01571                 }
01572                 bitmap += xjump; // needed if x<0 clipping occurs
01573             } else { /** ODD pixel starting line **/
01574                 uint8_t sourcepixel;
01575                 uint8_t targetpixel;
01576                 for (scrx = x; scrx < w+x-xclip; scrx+=2) {
01577                     sourcepixel = *bitmap;
01578                     targetpixel = *scrptr;
01579                     // store higher nibble of source pixel in lower nibble of target
01580                     if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel >> 4 );
01581                     *scrptr = targetpixel;
01582                     scrptr++;
01583                     targetpixel = *scrptr;
01584                     // store lower nibble of source pixel in higher nibble of target
01585                     if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel << 4);
01586                     *scrptr = targetpixel;
01587                     bitmap++;
01588                 }
01589                 if (xclip) {
01590                     // last line, store higher nibble of last source pixel in lower nibble of last address
01591                     sourcepixel = *bitmap >> 4;
01592                     if(sourcepixel!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | sourcepixel;
01593                     *scrptr = targetpixel;
01594                 }
01595                 bitmap+=xjump;
01596             }
01597             // increment the y jump in the scrptr
01598             scrptr = scrptr + ((width - w)>>1)+scrxjump;
01599     }
01600 
01601     return;
01602     }
01603 
01604     /** 4bpp fast version */
01605 
01606     if (m_colordepth==8) {
01607     int16_t scrx,scry,xclip,xjump,scrxjump;
01608     xclip=xjump=scrxjump=0;
01609     /** y clipping */
01610     if (y<0) { h+=y; bitmap -= y*w; y=0;}
01611     else if (y+h>height) { h -=(y-height);}
01612     /** x clipping */
01613     if (x<0) { xclip=x; w+=x; xjump = (-x); bitmap += xjump; x=0;}
01614     else if (x+w>width) {
01615             xclip = x;
01616             scrxjump = x;
01617             xjump=(x+w-width)+scrxjump;
01618             w = width-x;}
01619 
01620     uint8_t* scrptr = m_scrbuf + (y*width + x);
01621     for (scry = y; scry < y+h; scry+=1) {
01622             if (scry>=height) return;
01623                 for (scrx = x; scrx < w+x; scrx++) {
01624                     uint8_t sourcepixel = *bitmap;
01625                     uint8_t targetpixel = *scrptr;
01626                     if (sourcepixel != invisiblecolor ) targetpixel = sourcepixel;
01627                     *scrptr = targetpixel;
01628                     bitmap++;
01629                     scrptr++;
01630                 }
01631             bitmap += xjump; // needed if x<0 clipping occurs
01632         scrptr = scrptr + (width - w)+scrxjump;
01633     }
01634     return;
01635     }
01636 
01637 
01638 }
01639 
01640 void Display::drawRleBitmap(int16_t x, int16_t y, const uint8_t* rlebitmap)
01641 {
01642     // ONLY can copy 4-bit bitmap to 4-bit screen mode for time being
01643     #if (POK_SCREENMODE != MODE_FAST_16COLOR)
01644     return;
01645     #endif
01646 
01647     int16_t w = *rlebitmap;
01648     int16_t h = *(rlebitmap + 1);
01649     rlebitmap = rlebitmap + 2; //add an offset to the pointer to start after the width and height
01650 
01651     // visibility check
01652     if (y<-h || y>height) return; //invisible
01653     if (x<-w || x>width) return;  //invisible
01654 
01655     // Clipping is not supported
01656     if ((x < 0) || (x+w > width) || (y < 0) || (y+h > height)) return;
01657 
01658     // Currently only support RLE bitmaps in 16 color mode.
01659     if (m_colordepth != 4)  //
01660         return;
01661 
01662     // Go through each line.
01663     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
01664     bool is_endofbitmap = false;
01665     for (int16_t scry = y; scry < y+h && !is_endofbitmap;) {
01666 
01667         // Process one line. Go through each pixel run and escape command in RLE data.
01668         for (int16_t scrx = x;;) {
01669             uint8_t rle_count = *rlebitmap++;
01670 
01671             if (rle_count == 0) {
01672 
01673                /* Escape or absolute mode */
01674 
01675                 uint8_t rle_escape_or_runsize = *rlebitmap++;
01676                 if ( rle_escape_or_runsize == RLE_ESC_EOL) {
01677                     // End of line.
01678                     break;
01679                 }
01680                 else if ( rle_escape_or_runsize == RLE_ESC_EOB) {
01681                     // End of bitmap.
01682                     is_endofbitmap = true;
01683                     break;
01684                 }
01685                 else if ( rle_escape_or_runsize == RLE_ESC_OFFSET) {
01686                     // Move position in target.
01687                     // TODO: not tested yet.
01688                     uint8_t xoffset = *rlebitmap++;
01689                     uint8_t yoffset = *rlebitmap++;
01690                     scrptr += (xoffset>1);
01691                     scrx += xoffset;
01692                     scrptr += yoffset*width;
01693                     scry += yoffset;
01694                  }
01695                 else {
01696 
01697                     /* Absolute mode. Copy pixels from the source bitmap to the target screen. */
01698 
01699                     int16_t runsize = rle_escape_or_runsize;
01700                     uint8_t targetpixel = *scrptr;  // initial value
01701                     uint8_t sourcepixel = *rlebitmap;  // initial value
01702                     for( int16_t runx = 0; runx < runsize; ) {
01703                         if (scrx&0x1)  { // screen pixel is in the low nibble
01704                             if (runx&0x1) { // bitmap pixel is in the low nibble
01705                                 if ((sourcepixel&0x0F) != invisiblecolor)
01706                                     targetpixel = (targetpixel&0xF0) | (sourcepixel&0x0F); // Copy low to low nibble.
01707                                 rlebitmap++;
01708                             }
01709                             else // bitmap pixel is in the high nibble
01710                                 if ((sourcepixel>>4) != invisiblecolor)
01711                                     targetpixel = (targetpixel&0xF0) | (sourcepixel>>4); // Copy high to low nibble.
01712 
01713                             // Copy the byte to the target.
01714                             *scrptr = targetpixel;
01715                             scrptr++;
01716                         }
01717                         else  { // screen pixel is in the high nibble
01718                             targetpixel = *scrptr;
01719                             sourcepixel = *rlebitmap;
01720                             if (runx&0x1) { // bitmap pixel is sourcepixel = *rlebitmapin the low nibble
01721                                 if ((sourcepixel&0x0F) != invisiblecolor )
01722                                     targetpixel = (targetpixel&0x0F) | ((sourcepixel<<4)&0xF0); // Copy low to high nibble.
01723                                 rlebitmap++;  // read the new source byte
01724                             }
01725                             else // bitmap pixel is in the high nibble
01726                                 if ((sourcepixel>>4) != invisiblecolor )
01727                                     targetpixel = (targetpixel&0x0F) | (sourcepixel&0xF0); // Copy high to high nibble.
01728                         }
01729                         runx++;
01730                         scrx++;
01731                     }  // end for
01732 
01733                      // If this is odd target index, copy the byte to the target.
01734                     if (scrx&0x1) {
01735                         *scrptr = targetpixel;
01736                         scrptr++;
01737                     }
01738 
01739                     // In absolute mode the source size is always padded to the word boundary.
01740                     if (runsize%4) {
01741                         int16_t padpixcount = 4 - (runsize%4);
01742                         rlebitmap += padpixcount>>1;  // skip n padding bytes
01743                     }
01744                 }
01745             }
01746             else {
01747 
01748                 /* Encoded mode. Duplicate one pixel pair to the all required pixels on the target screen */
01749 
01750                 int16_t runsize = rle_count;
01751                 uint8_t clonepixelpair = *rlebitmap++;
01752                 uint8_t targetpixel = *scrptr;  // initial value
01753                 for( int16_t runx = 0;  runx < runsize; ) {
01754                     if (scrx&0x1)  { // screen pixel is in the low nibble
01755                         if (runx&0x1) { // bitmap pixel is in the low nibble
01756                             if ((clonepixelpair&0x0F) != invisiblecolor)
01757                                 targetpixel = (targetpixel&0xF0) | (clonepixelpair&0x0F); // Copy low to low nibble.
01758                         }
01759                         else // bitmap pixel is in the high nibble
01760                             if ((clonepixelpair>>4) != invisiblecolor)
01761                                 targetpixel = (targetpixel&0xF0) | (clonepixelpair>>4); // Copy high to low nibble.
01762 
01763                         // Copy the byte to the target.
01764                         *scrptr = targetpixel;
01765                         scrptr++;
01766                     }
01767                     else  { // screen pixel is in the high nibble
01768                         targetpixel = *scrptr;
01769                         if (runx&0x1) {// bitmap pixel is in the low nibble
01770                             if ((clonepixelpair&0x0F) != invisiblecolor )
01771                                 targetpixel = (targetpixel&0x0F) | ((clonepixelpair<<4)&0xF0); // Copy low to high nibble.
01772                         }
01773                         else // bitmap pixel is in the high nibble
01774                             if ((clonepixelpair>>4) != invisiblecolor )
01775                                 targetpixel = (targetpixel&0x0F) | (clonepixelpair&0xF0); // Copy high to high nibble.
01776                     }
01777                     runx++;
01778                     scrx++;
01779 
01780                 }  // end for
01781 
01782                 // If this is odd target index, copy the byte to the target.
01783                 if (scrx&0x1) {
01784                     *scrptr = targetpixel;
01785                     scrptr++;
01786                  }
01787             } // end if
01788         }  // end while
01789 
01790         // Increment the target screen pointer and index.
01791         scrptr = scrptr + ((width - w)>>1);
01792         scry++;
01793     } // end for scry
01794 }
01795 
01796 void Display::drawBitmapXFlipped(int16_t x, int16_t y, const uint8_t* bitmap)
01797 {
01798     int16_t w = *bitmap;
01799     int16_t h = *(bitmap + 1);
01800     bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
01801     /** visibility check */
01802     if (y<-h || y>height) return; //invisible
01803     if (x<-w || x>width) return;  //invisible
01804     /** 1 bpp mode */
01805     if (m_colordepth<2) {
01806     int16_t i, j, byteNum, bitNum, byteWidth = (w + 7) >> 3;
01807     for (i = 0; i < w; i++) {
01808         byteNum = i / 8;
01809         bitNum = i % 8;
01810         for (j = 0; j < h; j++) {
01811             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01812             if (source & (0x80 >> bitNum)) {
01813                 drawPixel(x + w - i, y + j);
01814             }
01815         }
01816     }
01817 
01818     return;
01819     }
01820     /** 2 bpp mode */
01821     if (m_colordepth<4) {
01822     int16_t i, j, byteNum, bitNum, byteWidth = w >> 2;
01823     for (i = 0; i < w; i++) {
01824         byteNum = i / 4;
01825         bitNum = (i % 4)<<1;
01826         for (j = 0; j < h; j++) {
01827             uint8_t source = *(bitmap + j * byteWidth + byteNum);
01828             uint8_t output = (source & (0xC0 >> bitNum));
01829             output >>= (6-bitNum);
01830             if (output != invisiblecolor) {
01831                 setColor(output);
01832                 drawPixel(x + i, y + j);
01833             }
01834         }
01835     }
01836 
01837     return;
01838     }
01839     /** 4bpp fast version */
01840     int16_t scrx,scry,xclip,xjump,scrxjump;
01841     xclip=xjump=scrxjump=0;
01842     /** y clipping */
01843     if (y<0) { h+=y; bitmap -= y*(w>>1); y=0;}
01844     else if (y+h>height) { h -=(y-height);}
01845     /** x clipping */
01846     bitmap += ((w>>1)-1); //inverted!
01847     if (x<0) {
01848             xclip=(x&1)<<1;
01849             w+=x;
01850             xjump = ((-x)>>1);
01851             //bitmap += xjump; // do not clip left edge of source, as bitmap is inverted !
01852             x=0;
01853             }
01854     else if (x+w>width) {
01855             xclip = (x&1)<<1;
01856             scrxjump = x&1;
01857             xjump=((x+w-width)>>1)+scrxjump;
01858             w = width-x;}
01859 
01860     //uint8_t* scrptr = m_scrbuf + (y*(width>>1) + ((x+width)>>1));
01861     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
01862     /** ONLY 4-bit mode for time being **/
01863     for (scry = y; scry < y+h; scry+=1) {
01864     //    for (scry = y; scry < y+2; scry+=1) {
01865             if (scry>=height) return;
01866             if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/
01867                 //for (scrx = w+x-xclip-1; scrx >= x; scrx-=2) {
01868                 for (scrx = x; scrx < w+x-xclip; scrx+=2) {
01869                     uint8_t sourcepixel = *(bitmap);
01870                     if (xclip) {
01871                             sourcepixel <<=4;
01872                             sourcepixel |= ((*(bitmap-1))>>4);//inverted!
01873                     }
01874                     uint8_t targetpixel = *scrptr;
01875                     // NIBBLES ARE INVERTED BECAUSE PICTURE IS FLIPPED !!!
01876                     if ((sourcepixel>>4) != invisiblecolor ) targetpixel = (targetpixel&0xF0) | (sourcepixel>>4);
01877                     if ((sourcepixel&0x0F) != invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel<<4);
01878                     *scrptr = targetpixel;
01879                     bitmap--;
01880                     scrptr++;
01881                 }
01882                 bitmap += w; // w*2 >> 1 because inverted and because 2 pixels per byte!!
01883                 if (xclip){
01884                     if (w&1) {
01885                         /**last pixel is odd pixel due to clipping & odd width*/
01886                         uint8_t sourcepixel = *bitmap;
01887                         if ((sourcepixel&0x0F) != invisiblecolor) {
01888                             sourcepixel <<=4;
01889                             uint8_t targetpixel = *scrptr;// & 0x0F;
01890                             targetpixel |= sourcepixel;
01891                             *scrptr = targetpixel;
01892                         }
01893                         //scrptr++;
01894                     }
01895                     bitmap++;
01896                     scrptr++;
01897                 }
01898                 bitmap += xjump; // needed if x<0 clipping occurs
01899             } else { /** ODD pixel starting line **/
01900                 for (scrx = x; scrx < w+x-xclip; scrx+=2 ) {
01901                     uint8_t sourcepixel = *bitmap;
01902                     uint8_t targetpixel = *scrptr;
01903                     // inverted !!! store lower nibble of source pixel in lower nibble of target
01904                     if((sourcepixel&0x0F)!=invisiblecolor) targetpixel = (targetpixel & 0xF0) | (sourcepixel & 0x0F );
01905                     *scrptr = targetpixel;
01906                     scrptr++;
01907                     targetpixel = *scrptr;
01908                     // inverted ! store higher nibble of source pixel in higher nibble of target
01909                     if((sourcepixel>>4)!=invisiblecolor) targetpixel = (targetpixel & 0x0F) | (sourcepixel & 0xF0);
01910                     *scrptr = targetpixel;
01911                     bitmap--;
01912                 }
01913                 bitmap += w; // w*2 >> 1 because inverted and because 2 pixels per byte!!
01914                 bitmap+=xjump;
01915             }
01916             // increment the y jump in the scrptr
01917             scrptr = scrptr + ((width - w)>>1)+scrxjump;
01918     }
01919 }
01920 
01921 void Display::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t rotation, uint8_t flip) {
01922 #if PROJ_GAMEBUINO == 0
01923     if (!flip) drawBitmap(x,y,bitmap);
01924     else drawBitmapXFlipped(x,y,bitmap);
01925 #else
01926     if((rotation == NOROT) && (flip == NOFLIP)){
01927         drawBitmap(x,y,bitmap); //use the faster algorithm
01928         return;
01929     }
01930     uint8_t w = bitmap[0];
01931     uint8_t h = bitmap[1];
01932     bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
01933     int8_t i, j, //coordinates in the raw bitmap
01934             k, l, //coordinates in the rotated/flipped bitmap
01935             byteNum, bitNum, byteWidth = (w + 7) >> 3;
01936 
01937     rotation %= 4;
01938 
01939     for (i = 0; i < w; i++) {
01940         byteNum = i / 8;
01941         bitNum = i % 8;
01942         for (j = 0; j < h; j++) {
01943             if (bitmap[j * byteWidth + byteNum] & (B10000000 >> bitNum)) {
01944                 switch (rotation) {
01945                     case NOROT: //no rotation
01946                         k = i;
01947                         l = j;
01948                         break;
01949                     case ROTCCW: //90° counter-clockwise
01950                         k = j;
01951                         l = w - i - 1;
01952                         break;
01953                     case ROT180: //180°
01954                         k = w - i - 1;
01955                         l = h - j - 1;
01956                         break;
01957                     case ROTCW: //90° clockwise
01958                         k = h - j - 1;
01959                         l = i;
01960                         break;
01961                 }
01962                 if (flip) {
01963                     flip %= 4;
01964                     if (flip & B00000001) { //horizontal flip
01965                         k = w - k;
01966                     }
01967                     if (flip & B00000010) { //vertical flip
01968                         l = h - l;
01969                     }
01970                 }
01971                 k += x; //place the bitmap on the screen
01972                 l += y;
01973                 drawPixel(k, l);
01974             }
01975         }
01976     }
01977 #endif //PROJ_GAMEBUINO
01978 
01979 }
01980 
01981 uint8_t* Display::getBuffer() {
01982     return m_scrbuf;
01983 }
01984 
01985 uint8_t Display::getBitmapPixel(const uint8_t* bitmap, uint16_t x, uint16_t y) {
01986     uint16_t w = *bitmap;
01987     uint8_t sourcebyte = bitmap[2+(y * ((w+7)>>3))+ (x>>3)];
01988     return sourcebyte & (0x80>>(x&7));
01989 }
01990 
01991 int Display::print_char(uint8_t x, uint8_t y, unsigned char c) {
01992     c -= font[2];
01993     if (m_mode) return directChar(x,y,c);
01994     return bufferChar(x,y,c);
01995 }
01996 
01997 void Display::drawChar(int8_t x, int8_t y, unsigned char c, uint8_t size) {
01998     print_char(x,y,c);
01999     return;
02000 }
02001 
02002 
02003 bool Display::isDirectPrintingEnabled() {
02004     return m_mode;
02005 }
02006 
02007 void Display::enableDirectPrinting(uint8_t m) {
02008     if (m) {
02009             m_mode=true;
02010             m_w = POK_LCD_W;
02011             m_h = POK_LCD_H;
02012     } else {
02013             m_mode=false;
02014             m_w = getWidth();
02015             m_h = getHeight();
02016     }
02017 }
02018 
02019 void Display::write(uint8_t c) {
02020     int charstep=0;
02021     if(font[3]) {
02022         // only caps in this font
02023         if (c>=97) c-=32;
02024     }
02025     switch(c) {
02026         case '\0':          //null
02027             break;
02028         case '\n':          //line feed
02029             cursorX = 0;
02030             inc_txtline();
02031             break;
02032         case 8:             //backspace
02033             cursorX -= font[0];
02034             charstep=print_char(cursorX,cursorY,' ');
02035             break;
02036         case 13:            //carriage return
02037             cursorX = 0;
02038             break;
02039         case 14:            //form feed new page(clear screen)
02040             //clear_screen();
02041             break;
02042         default:
02043             if (cursorX >= (m_w - font[0])) {
02044                 cursorX = 0;
02045                 if (textWrap) inc_txtline();
02046                 else return; // stop outputting text
02047                 charstep=print_char(cursorX,cursorY,c);
02048             }
02049             else
02050                 charstep=print_char(cursorX,cursorY,c);
02051             #ifndef FULLWIDTHSPACES
02052             if (c==' ' && adjustCharStep) charstep=(charstep>>1)+1;
02053             #endif
02054             cursorX += charstep;
02055     }
02056 }
02057 
02058 void Display::inc_txtline() {
02059     if (cursorY > m_h - 2*font[1]) //= (height - (font[1]+1)))
02060         #if SCROLL_TEXT > 0
02061         scroll(font[1] + adjustLineStep);
02062         #else
02063         cursorY = 0;
02064         #endif
02065     else
02066         cursorY += font[1] + adjustLineStep;
02067 }
02068 
02069 /* default implementation: may be overridden */
02070 void Display::write(const char *str)
02071 {
02072   while (*str)
02073     write(*str++);
02074 }
02075 
02076 /* default implementation: may be overridden */
02077 void Display::write(const uint8_t *buffer, uint8_t size)
02078 {
02079   while (size--)
02080     write(*buffer++);
02081 }
02082 
02083 void Display::print(const char str[])
02084 {
02085   write(str);
02086 }
02087 
02088 void Display::print(char c, int base)
02089 {
02090   print((long) c, base);
02091 }
02092 
02093 void Display::print(unsigned char b, int base)
02094 {
02095   print((unsigned long) b, base);
02096 }
02097 
02098 void Display::print(int n, int base)
02099 {
02100   print((long) n, base);
02101 }
02102 
02103 void Display::print(unsigned int n, int base)
02104 {
02105   print((unsigned long) n, base);
02106 }
02107 
02108 void Display::print(long n, int base)
02109 {
02110   if (base == 0) {
02111     write(n);
02112   } else if (base == 10) {
02113     if (n < 0) {
02114       print('-');
02115       n = -n;
02116     }
02117     printNumber(n, 10);
02118   } else {
02119     printNumber(n, base);
02120   }
02121 }
02122 
02123 void Display::print(unsigned long n, int base)
02124 {
02125   if (base == 0) write(n);
02126   else printNumber(n, base);
02127 }
02128 
02129 void Display::print(double n, int digits)
02130 {
02131   printFloat(n, digits);
02132 }
02133 
02134 void Display::println(void)
02135 {
02136   print('\r');
02137   print('\n');
02138 }
02139 
02140 void Display::println(const char c[])
02141 {
02142   print(c);
02143   println();
02144 }
02145 
02146 void Display::println(char c, int base)
02147 {
02148   print(c, base);
02149   println();
02150 }
02151 
02152 void Display::println(unsigned char b, int base)
02153 {
02154   print(b, base);
02155   println();
02156 }
02157 
02158 void Display::println(int n, int base)
02159 {
02160   print(n, base);
02161   println();
02162 }
02163 
02164 void Display::println(unsigned int n, int base)
02165 {
02166   print(n, base);
02167   println();
02168 }
02169 
02170 void Display::println(long n, int base)
02171 {
02172   print(n, base);
02173   println();
02174 }
02175 
02176 void Display::println(unsigned long n, int base)
02177 {
02178   print(n, base);
02179   println();
02180 }
02181 
02182 void Display::println(double n, int digits)
02183 {
02184   print(n, digits);
02185   println();
02186 }
02187 
02188 void Display::set_cursor(uint8_t x, uint8_t y) {
02189     cursorX = x;
02190     cursorY = y;
02191 }
02192 
02193 void Display::print(uint8_t x, uint8_t y, const char str[]) {
02194     cursorX = x;
02195     cursorY = y;
02196     write(str);
02197 
02198 }
02199 void Display::print(uint8_t x, uint8_t y, char c, int base) {
02200     cursorX = x;
02201     cursorY = y;
02202     print((long) c, base);
02203 }
02204 void Display::print(uint8_t x, uint8_t y, unsigned char b, int base) {
02205     cursorX = x;
02206     cursorY = y;
02207     print((unsigned long) b, base);
02208 }
02209 void Display::print(uint8_t x, uint8_t y, int n, int base) {
02210     cursorX = x;
02211     cursorY = y;
02212     print((long) n, base);
02213 }
02214 void Display::print(uint8_t x, uint8_t y, unsigned int n, int base) {
02215     cursorX = x;
02216     cursorY = y;
02217     print((unsigned long) n, base);
02218 }
02219 void Display::print(uint8_t x, uint8_t y, long n, int base) {
02220     cursorX = x;
02221     cursorY = y;
02222     print(n,base);
02223 }
02224 void Display::print(uint8_t x, uint8_t y, unsigned long n, int base) {
02225     cursorX = x;
02226     cursorY = y;
02227     print(n,base);
02228 }
02229 void Display::print(uint8_t x, uint8_t y, double n, int digits) {
02230     cursorX = x;
02231     cursorY = y;
02232     print(n,digits);
02233 }
02234 
02235 void Display::println(uint8_t x, uint8_t y, const char c[])
02236 {
02237     cursorX = x;
02238     cursorY = y;
02239     print(c);
02240     println();
02241 }
02242 
02243 void Display::println(uint8_t x, uint8_t y, char c, int base)
02244 {
02245     cursorX = x;
02246     cursorY = y;
02247     print(c, base);
02248     println();
02249 }
02250 
02251 void Display::println(uint8_t x, uint8_t y, unsigned char b, int base)
02252 {
02253     cursorX = x;
02254     cursorY = y;
02255     print(b, base);
02256     println();
02257 }
02258 
02259 void Display::println(uint8_t x, uint8_t y, int n, int base)
02260 {
02261     cursorX = x;
02262     cursorY = y;
02263     print(n, base);
02264     println();
02265 }
02266 
02267 void Display::println(uint8_t x, uint8_t y, unsigned int n, int base)
02268 {
02269     cursorX = x;
02270     cursorY = y;
02271     print(n, base);
02272     println();
02273 }
02274 
02275 void Display::println(uint8_t x, uint8_t y, long n, int base)
02276 {
02277     cursorX = x;
02278     cursorY = y;
02279     print(n, base);
02280     println();
02281 }
02282 
02283 void Display::println(uint8_t x, uint8_t y, unsigned long n, int base)
02284 {
02285     cursorX = x;
02286     cursorY = y;
02287     print(n, base);
02288     println();
02289 }
02290 
02291 void Display::println(uint8_t x, uint8_t y, double n, int digits)
02292 {
02293     cursorX = x;
02294     cursorY = y;
02295     print(n, digits);
02296     println();
02297 }
02298 
02299 void Display::printNumber(unsigned long n, uint8_t base)
02300 {
02301   unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
02302   unsigned long i = 0;
02303 
02304   if (n == 0) {
02305     print('0');
02306     return;
02307   }
02308 
02309   while (n > 0) {
02310     buf[i++] = n % base;
02311     n /= base;
02312   }
02313 
02314   for (; i > 0; i--)
02315     print((char) (buf[i - 1] < 10 ?
02316       '0' + buf[i - 1] :
02317       'A' + buf[i - 1] - 10));
02318 }
02319 
02320 void Display::printFloat(double number, uint8_t digits)
02321 {
02322   // Handle negative numbers
02323   if (number < 0.0)
02324   {
02325      print('-');
02326      number = -number;
02327   }
02328 
02329   // Round correctly so that print(1.999, 2) prints as "2.00"
02330   double rounding = 0.5;
02331   for (uint8_t i=0; i<digits; ++i)
02332     rounding /= 10.0;
02333 
02334   number += rounding;
02335 
02336   // Extract the integer part of the number and print it
02337   unsigned long int_part = (unsigned long)number;
02338   double remainder = number - (double)int_part;
02339   print(int_part);
02340 
02341   // Print the decimal point, but only if there are digits beyond
02342   if (digits > 0)
02343     print(".");
02344 
02345   // Extract digits from the remainder one at a time
02346   while (digits-- > 0)
02347   {
02348     remainder *= 10.0;
02349     int toPrint = int(remainder);
02350     print(toPrint);
02351     remainder -= toPrint;
02352   }
02353 }
02354 
02355 
02356 void Display::draw4BitColumn(int16_t x, int16_t y, uint8_t h, uint8_t* bitmap)
02357 {
02358     int8_t scry;
02359     uint8_t* scrptr = m_scrbuf + (y*(width>>1) + (x>>1));
02360 
02361     /** ONLY 4-bit mode for time being **/
02362 
02363             if ((x&1)==0) { /** EVEN pixel starting line, very simple, just copypaste **/
02364                 for (scry = y; scry < h+y; scry++) {
02365                     uint8_t sourcepixel = *bitmap;
02366                     uint8_t targetpixel = *scrptr;
02367                     targetpixel = (targetpixel&0x0F) | (sourcepixel << 4);
02368                     *scrptr = targetpixel;
02369                     bitmap++;
02370                     scrptr+=55;
02371                 }
02372             } else { /** ODD pixel starting line **/
02373                 for (scry = y; scry < h+y; scry++) {
02374                     uint8_t sourcepixel = *bitmap;
02375                     uint8_t targetpixel = *scrptr;
02376                     // store source pixel in lower nibble of target
02377                     targetpixel = (targetpixel & 0xF0) | (sourcepixel);
02378                     *scrptr = targetpixel;
02379                     scrptr+=55;
02380                     bitmap++;
02381                 }
02382             }
02383 }
02384 
02385 /**
02386  * Setup or disable the sprite. Note that enabled sprites must always have subsequent indices, starting from the index zero.
02387  * You cannot have gaps in indices of enabled sprites.
02388  * The max number of sprites can be changed by a SPRITE_COUNT define, the default is 4.
02389  * Note: the sprites currently work only in the 220 x 176 x 2bpp mode.
02390  * @param index The sprite index. The lower index is drawn first, i.e. is on bottom.
02391  * @param bitmap A pointer to a 2bpp bitmap. A NULL value means that the sprite is disabled. The ownership is not transferred, so the caller must keep the bitmap alive.
02392  * @param palette4x16bit Four color palette of 16bit elements. The first color value is considered as transparent. The palette is copied to the sprite struct, so the caller do not have to keep it alive.
02393  * @param x The initial x
02394  * @param y The initial y
02395  * @param doResetDirtyRect (default=true) True, if the previous coordinates are reseted.
02396  */
02397 void Display::setSpriteBitmap(uint8_t index, const uint8_t* bitmap,  const uint16_t* palette4x16bit, int16_t x, int16_t y, bool doResetDirtyRect ) {
02398 
02399     setSprite(index, &(bitmap[2]), palette4x16bit, x, y, bitmap[0], bitmap[1], doResetDirtyRect);
02400 }
02401 
02402 /**
02403  * Setup or disable the sprite. Note that enabled sprites must always have subsequent indices, starting from the index zero.
02404  * You cannot have gaps in indices of enabled sprites.
02405  * The max number of sprites can be changed by a SPRITE_COUNT define, the default is 4.
02406  * Note: the sprites currently work only in the 220 x 176 x 2bpp mode.
02407  * @param index The sprite index. The lower index is drawn first, i.e. is on bottom. Note that
02408  * @param data A pointer to a 2bpp pixel data of size w x h. A NULL value means that the sprite is disabled. The ownership is not transferred, so the caller must keep the data alive.
02409  * @param palette4x16bit Four color palette of 16bit elements. The first color value is considered as transparent. The palette is copied to the sprite struct, so the caller do not have to keep it alive.
02410  * @param x The initial x
02411  * @param y The initial y
02412  * @param w Width
02413  * @param h Height
02414  */
02415 void Display::setSprite(uint8_t index, const uint8_t* data, const uint16_t* palette4x16bit, int16_t x, int16_t y, uint8_t w, uint8_t h, bool doResetDirtyRect ) {
02416 
02417     if(index >= SPRITE_COUNT) return;
02418     m_sprites[index].bitmapData = data;
02419     m_sprites[index].x = x;
02420     m_sprites[index].y = y;
02421     if (doResetDirtyRect) {
02422         m_sprites[index].oldx = x;
02423         m_sprites[index].oldy = y;
02424     }
02425     m_sprites[index].w = w;
02426     m_sprites[index].h = h;
02427     if( palette4x16bit ) memcpy(m_sprites[index].palette, palette4x16bit, 4*2);
02428 }
02429 
02430 /**
02431  * Set the sprite position.
02432  * @param index The sprite index
02433  * @param x
02434  * @param y
02435  */
02436 void Display::setSpritePos(uint8_t index, int16_t x, int16_t y) {
02437 
02438     if(index >= SPRITE_COUNT) return;
02439     m_sprites[index].x = x;
02440     m_sprites[index].y = y;
02441 }
02442 
02443 void Display::lcdRefresh(unsigned char* scr, bool useDirectDrawMode) {
02444 
02445 #if POK_SCREENMODE == MODE_HI_4COLOR
02446     // If there is one or more sprites, use sprite enabled drawing.
02447     if (m_sprites[0].bitmapData != NULL)
02448         lcdRefreshMode1Spr(scr, 0, 0, LCDWIDTH, LCDHEIGHT, paletteptr, m_sprites, useDirectDrawMode);
02449     else if (!useDirectDrawMode)
02450         lcdRefreshMode1(m_scrbuf, 0, 0, LCDWIDTH, LCDHEIGHT, paletteptr);
02451 #endif
02452 
02453     // For the screen modes that do not support sprites, return if the direct draw mode is used.
02454     if (useDirectDrawMode) return;
02455 #if POK_SCREENMODE == MODE13
02456     lcdRefreshMode13(m_scrbuf, paletteptr, palOffset);
02457 #endif
02458 
02459 #if POK_SCREENMODE == MIXMODE
02460     lcdRefreshMixMode(m_scrbuf, paletteptr, scanType);
02461 #endif
02462 
02463 #if POK_SCREENMODE == MODE64
02464     lcdRefreshMode64(m_scrbuf, paletteptr);
02465 #endif
02466 
02467 #if POK_SCREENMODE == MODE_GAMEBOY
02468     lcdRefreshModeGBC(scr, paletteptr);
02469 #endif
02470 
02471 #if POK_SCREENMODE == MODE_FAST_16COLOR
02472     lcdRefreshMode2(scr, paletteptr);
02473 #endif
02474 
02475 #if POK_SCREENMODE == MODE_GAMEBUINO_16COLOR
02476     lcdRefreshGB(scr, paletteptr);
02477 #endif
02478 
02479 #if POK_SCREENMODE == MODE_ARDUBOY_16COLOR
02480     lcdRefreshAB(scr, paletteptr);
02481 #endif
02482 
02483 }
02484 
02485 void Display::setFrameBufferTo(uint8_t* sb) {
02486     m_scrbuf = sb;
02487 };
02488 
02489 void Display::setTileBufferTo(uint8_t* tb) {
02490     m_tilebuf = tb;
02491 };
02492 
02493 void Display::loadTileset(const uint8_t* ts) {
02494     m_tileset = (uint8_t*) ts;
02495 };
02496 
02497 void Display::setTile(uint16_t i, uint8_t t) {
02498     if (!m_tilebuf) return;
02499     m_tilebuf[i]=t;
02500 };
02501 
02502 
02503 
02504 // Convert an integer to a hexadecimal string
02505 char* itoa_hex(int num, char* dest, int destLen) {
02506     int i = destLen-1;
02507     do {
02508         char c = (num % 16) + '0';
02509         if (c > '9') c += 7;
02510         dest[i--] = c;
02511         num /= 16;
02512     } while (num && i >= 0);
02513     return &(dest[i+1]);
02514 }
02515 
02516 // Draw the crash screen and wait forever
02517 void ShowCrashScreenAndWait( const char* texLine1, const char* texLine2, const char* texLine3, const char* texLine4, const char* texLine5 ) {
02518 
02519     // draw screen red
02520     lcdFillSurface(COLOR_RED);
02521 
02522     // Draw text
02523     Display::directcolor = COLOR_WHITE;
02524     Display::invisiblecolor = COLOR_RED;
02525     Display::directbgcolor = COLOR_RED; // Cannot be black as that is a transparent color
02526     Display::directtextrotated = false;
02527     Display::adjustCharStep = 0;
02528     Display::adjustLineStep = 0;
02529     Display::setFont(fntC64UIGfx);  // A special font set that contains UI gfx in lower case letters.
02530     Display::fixedWidthFont = true; // Needed for the non-proportional C64 font (default value=false)
02531     Display::enableDirectPrinting(true);
02532 
02533     // Draw texts
02534     int  yOffsetInPixels = 5;
02535     Display::set_cursor(0, 9 + yOffsetInPixels);
02536     Display::print("  ");    Display::println(texLine1);
02537     Display::print("  ");    Display::println(texLine2);
02538     Display::print("  ");    Display::println(texLine3);
02539     Display::println();
02540     Display::print("  *");   Display::println(texLine4);
02541     Display::print("  *");   Display::println(texLine5);
02542 
02543     Display::set_cursor(0, 0 + yOffsetInPixels);
02544 
02545     // Frame
02546     Display::println(" abbbbbbbbbbbbbbbbbbbbbbbbc");
02547     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02548     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02549     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02550     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02551     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02552     Display::print  (" |"); Display::println(26*8, Display::cursorY,"|");
02553     Display::println(" dbbbzybbbbbbbbbbbbbbbbbbbe");
02554     Display::println("     {e");
02555 
02556      // Pokitto image
02557     Display::println  ("");
02558     Display::println  ("  ijkl");
02559     Display::println  ("  mnop");
02560     Display::println  ("  qrst");
02561     Display::println  ("  uvwx");
02562 
02563    // loop forever
02564     while(1){;}
02565  }
02566 
02567 // Check the stack size and show a crash screen if the stack is too big.
02568 void CheckStack() {
02569     #ifndef POK_SIM
02570     #ifndef __ARMCC_VERSION
02571     int currStackTop;
02572     const int freeStackThreshold = 200;
02573     if ((int)&currStackTop - (int)_ebss < freeStackThreshold) {
02574 
02575         // Create info string: "<stack size>:<current stack pointer>", e.g. "12345ABC:12345ABC"
02576         const int infoStringLen = 8+1+8;
02577         static char infoString[infoStringLen+1];
02578         memset(infoString,0,infoStringLen+1);
02579         const int stackSize = (int)_vStackTop - (int)&currStackTop;
02580         const int tmpStrLen = 8;
02581         static char tmpStr[tmpStrLen+1];
02582         memset(tmpStr,0,tmpStrLen+1);
02583         char* subStr = itoa_hex(stackSize, tmpStr, tmpStrLen); // keep ending null
02584         strcat(infoString, subStr); // Add stack size as hex string
02585         strcat(infoString, ":");
02586         subStr = itoa_hex((int)&currStackTop, tmpStr, tmpStrLen); // keep ending null
02587         strcat(infoString, subStr); // Add stack pointer address as hex string
02588 
02589         // Draw the crash screen and wait forever. Use static const strings to avoid more stack usage.
02590         static const char* texLine1 = "OOPS! PLEASE, RESTART";
02591         static const char* texLine2 = "POKITTO OR RELOAD";
02592         static const char* texLine3 = "SOFTWARE.";
02593         static const char* texLine4 = "STACK TOO BIG!";
02594         ShowCrashScreenAndWait(texLine1, texLine2, texLine3, texLine4, infoString);
02595     }
02596     #endif
02597     #endif
02598 }
02599 
02600 /** Eof */
02601 
02602 
02603 
02604