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

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

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