Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

charset.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2005 The ScummVM project
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/charset.cpp,v 2.154.2.1 2005/10/18 02:11:21 sev Exp $
 */

#include "common/stdafx.h"
#include "scumm/charset.h"
#include "scumm/scumm.h"
#include "scumm/nut_renderer.h"
#include "scumm/util.h"
#include "scumm/wiz_he.h"

namespace Scumm {

void ScummEngine::loadCJKFont() {
      Common::File fp;
      _useCJKMode = false;
      if (_language == Common::JA_JPN && _version <= 5) { // FM-TOWNS v3 / v5 Kanji
            int numChar = 256 * 32;
            _2byteWidth = 16;
            _2byteHeight = 16;
            // use FM-TOWNS font rom, since game files don't have kanji font resources
            if (fp.open("fmt_fnt.rom", Common::File::kFileReadMode)) {
                  _useCJKMode = true;
                  debug(2, "Loading FM-TOWNS Kanji rom");
                  _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar];
                  fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar);
                  fp.close();
            }
      } else if (_language == Common::KO_KOR || _language == Common::JA_JPN || _language == Common::ZH_TWN) {
            int numChar = 0;
            const char *fontFile = NULL;

            switch (_language) {
            case Common::KO_KOR:
                  fontFile = "korean.fnt";
                  numChar = 2350;
                  break;
            case Common::JA_JPN:
                  fontFile = (_gameId == GID_DIG) ? "kanji16.fnt" : "japanese.fnt";
                  numChar = 1024; //FIXME
                  break;
            case Common::ZH_TWN:
                  if (_gameId == GID_CMI) {
                        fontFile = "chinese.fnt";
                        numChar = 1; //FIXME
                  }
                  break;
            default:
                  break;
            }
            if (fontFile && fp.open(fontFile)) {
                  debug(2, "Loading CJK Font");
                  _useCJKMode = true;
                  fp.seek(2, SEEK_CUR);
                  _2byteWidth = fp.readByte();
                  _2byteHeight = fp.readByte();

                  _2byteFontPtr = new byte[((_2byteWidth + 7) / 8) * _2byteHeight * numChar];
                  fp.read(_2byteFontPtr, ((_2byteWidth + 7) / 8) * _2byteHeight * numChar);
                  fp.close();
            } else {
                  error("Couldn't load any font");
            }
      }
}

static int SJIStoFMTChunk(int f, int s) { //converts sjis code to fmt font offset
      enum {
            KANA = 0,
            KANJI = 1,
            EKANJI = 2
      };
      int base = s - ((s + 1) % 32);
      int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;

      if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
      if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
      if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;

      if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
            c = 48; //correction
            p = -8; //correction
      }

      if (kanjiType == KANA) {//Kana
            chunk_f = (f - 0x81) * 2;
      } else if (kanjiType == KANJI) {//Standard Kanji
            p += f - 0x88;
            chunk_f = c + 2 * p;
      } else if (kanjiType == EKANJI) {//Enhanced Kanji
            p += f - 0xe0;
            chunk_f = c + 2 * p;
      }

      // Base corrections
      if (base == 0x7f && s == 0x7f)
            base -= 0x20;
      if (base == 0x9f && s == 0xbe)
            base += 0x20;
      if (base == 0xbf && s == 0xde)
            base += 0x20;
      //if (base == 0x7f && s == 0x9e)
      //    base += 0x20;

      switch (base) {
      case 0x3f:
            cr = 0; //3f
            if (kanjiType == KANA) chunk = 1;
            else if (kanjiType == KANJI) chunk = 31;
            else if (kanjiType == EKANJI) chunk = 111;
            break;
      case 0x5f:
            cr = 0; //5f
            if (kanjiType == KANA) chunk = 17;
            else if (kanjiType == KANJI) chunk = 47;
            else if (kanjiType == EKANJI) chunk = 127;
            break;
      case 0x7f:
            cr = -1; //80
            if (kanjiType == KANA) chunk = 9;
            else if (kanjiType == KANJI) chunk = 63;
            else if (kanjiType == EKANJI) chunk = 143;
            break;
      case 0x9f:
            cr = 1; //9e
            if (kanjiType == KANA) chunk = 2;
            else if (kanjiType == KANJI) chunk = 32;
            else if (kanjiType == EKANJI) chunk = 112;
            break;
      case 0xbf:
            cr = 1; //be
            if (kanjiType == KANA) chunk = 18;
            else if (kanjiType == KANJI) chunk = 48;
            else if (kanjiType == EKANJI) chunk = 128;
            break;
      case 0xdf:
            cr = 1; //de
            if (kanjiType == KANA) chunk = 10;
            else if (kanjiType == KANJI) chunk = 64;
            else if (kanjiType == EKANJI) chunk = 144;
            break;
      default:
            error("Invaild Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
            return 0;
      }

      debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
      return ((chunk_f + chunk) * 32 + (s - base)) + cr;
}

byte *ScummEngine::get2byteCharPtr(int idx) {
      switch (_language) {
      case Common::KO_KOR:
            idx = ((idx % 256) - 0xb0) * 94 + (idx / 256) - 0xa1;
            break;
      case Common::JA_JPN:
            idx = SJIStoFMTChunk((idx % 256), (idx / 256));
            break;
      case Common::ZH_TWN:
      default:
            idx = 0;
      }
      return      _2byteFontPtr + ((_2byteWidth + 7) / 8) * _2byteHeight * idx;
}


#pragma mark -


CharsetRenderer::CharsetRenderer(ScummEngine *vm) {

      _nextLeft = 0;
      _nextTop = 0;

      _top = 0;
      _left = 0;
      _startLeft = 0;
      _right = 0;

      _color = 0;

      _center = false;
      _hasMask = false;
      _textScreenID = kMainVirtScreen;
      _ignoreCharsetMask = false;
      _blitAlso = false;
      _firstChar = false;
      _disableOffsX = false;

      _vm = vm;
      _curId = 0;

      const int size = _vm->_screenWidth * _vm->_screenHeight;
      _textSurface.pixels = malloc(size);
      _textSurface.w = _vm->_screenWidth;
      _textSurface.h = _vm->_screenHeight;
      _textSurface.pitch = _vm->_screenWidth;
      _textSurface.bytesPerPixel = 1;
      clearTextSurface();
}

CharsetRenderer::~CharsetRenderer() {
      free(_textSurface.pixels);
}

CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm)
      : CharsetRenderer(vm), _numChars(0), _fontHeight(0) {
      _shadowMode = kNoShadowMode;
      _shadowColor = 0;
}

void CharsetRendererCommon::setCurID(byte id) {
      checkRange(_vm->_numCharsets - 1, 0, id, "Printing with bad charset %d");

      _curId = id;

      _fontPtr = _vm->getResourceAddress(rtCharset, id);
      if (_fontPtr == 0)
            error("CharsetRendererCommon::setCurID: charset %d not found!", id);

      if (_vm->_version == 4)
            _fontPtr += 17;
      else
            _fontPtr += 29;

      //_bitDepth = _fontPtr[0];
      _fontHeight = _fontPtr[1];
      _numChars = READ_LE_UINT16(_fontPtr + 2);
}

void CharsetRendererV3::setCurID(byte id) {
      checkRange(_vm->_numCharsets - 1, 0, id, "Printing with bad charset %d");

      _curId = id;

      _fontPtr = _vm->getResourceAddress(rtCharset, id);
      if (_fontPtr == 0)
            error("CharsetRendererCommon::setCurID: charset %d not found!", id);

      //_bitDepth = 1;
      _numChars = _fontPtr[4];
      _fontHeight = _fontPtr[5];

      _fontPtr += 6;
      _widthTable = _fontPtr;
      _fontPtr += _numChars;
}

int CharsetRendererCommon::getFontHeight() {
      if (_vm->_useCJKMode)
            return MAX(_vm->_2byteHeight + 1, _fontHeight);
      else
            return _fontHeight;
}

int CharsetRendererV3::getFontHeight() {
      if (_vm->_useCJKMode)
            return MAX(_vm->_2byteHeight + 1, _fontHeight);
      else
            return _fontHeight;
}

// do spacing for variable width old-style font
int CharsetRendererClassic::getCharWidth(byte chr) {
      if (chr >= 0x80 && _vm->_useCJKMode)
            return _vm->_2byteWidth / 2;
      int spacing = 0;

      int offs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
      if (offs) {
            spacing = _fontPtr[offs] + (signed char)_fontPtr[offs + 2];
      }

      return spacing;
}

int CharsetRenderer::getStringWidth(int arg, const byte *text) {
      int pos = 0;
      int width = 1;
      byte chr;
      int oldID = getCurID();
      int code = (_vm->_heversion >= 80) ? 127 : 64;

      while ((chr = text[pos++]) != 0) {
            if (_vm->_heversion >= 72 && chr == code) {
                  chr = text[pos++];
                  if (chr == 84) {  // Strings of speech offset/size
                        while (chr != code)
                              chr = text[pos++];
                        continue;
                  }
                  if (chr == 119) // 'Wait'
                        break;
                  if (chr == 104|| chr == 110) // 'Newline'
                        break;
            } else if (chr == '@')
                  continue;
            if (chr == '\n' || chr == '\r')
                  break;
            if (chr == 254 || chr == 255) {
                  //process in LE
                  if (chr == 254 && checkKSCode(text[pos], chr) && _vm->_useCJKMode) {
                        goto loc_avoid_ks_fe;
                  }
                  chr = text[pos++];
                  if (chr == 3)     // 'WAIT'
                        break;
                  if (chr == 8) { // 'Verb on next line'
                        if (arg == 1)
                              break;
                        while (text[pos++] == ' ')
                              ;
                        continue;
                  }
                  if (chr == 10 || chr == 21 || chr == 12 || chr == 13) {
                        pos += 2;
                        continue;
                  }
                  if (chr == 9 || chr == 1 || chr == 2) // 'Newline'
                        break;
                  if (chr == 14) {
                        int set = text[pos] | (text[pos + 1] << 8);
                        pos += 2;
                        setCurID(set);
                        continue;
                  }
            }
loc_avoid_ks_fe:
            if ((chr & 0x80) && _vm->_useCJKMode) {
                  pos++;
                  width += _vm->_2byteWidth;
            } else {
                  width += getCharWidth(chr);
            }
      }

      setCurID(oldID);

      return width;
}

void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
      int lastspace = -1;
      int curw = 1;
      byte chr;
      int oldID = getCurID();
      int code = (_vm->_heversion >= 80) ? 127 : 64;

      while ((chr = str[pos++]) != 0) {
            if (_vm->_heversion >= 72 && chr == code) {
                  chr = str[pos++];
                  if (chr == 84) {  // Strings of speech offset/size
                        while (chr != code)
                              chr = str[pos++];
                        continue;
                  }
                  if (chr == 119) // 'Wait'
                        break;
                  if (chr == 110) { // 'Newline'
                        curw = 1;
                        continue;
                  }
                  if (chr == 104) // 'Don't terminate with \n'
                        break;
            } else if (chr == '@')
                  continue;
            if (chr == 254 || chr == 255) {
                  //process in LE
                  if (chr == 254 && checkKSCode(str[pos], chr) && _vm->_useCJKMode) {
                        goto loc_avoid_ks_fe;
                  }
                  chr = str[pos++];
                  if (chr == 3) // 'Wait'
                        break;
                  if (chr == 8) { // 'Verb on next line'
                        if (a == 1) {
                              curw = 1;
                        } else {
                              while (str[pos] == ' ')
                                    str[pos++] = '@';
                        }
                        continue;
                  }
                  if (chr == 10 || chr == 21 || chr == 12 || chr == 13) {
                        pos += 2;
                        continue;
                  }
                  if (chr == 1) { // 'Newline'
                        curw = 1;
                        continue;
                  }
                  if (chr == 2) // 'Don't terminate with \n'
                        break;
                  if (chr == 14) {
                        int set = str[pos] | (str[pos + 1] << 8);
                        pos += 2;
                        setCurID(set);
                        continue;
                  }
            }

            if (chr == ' ')
                  lastspace = pos - 1;

loc_avoid_ks_fe:
            if ((chr & 0x80) && _vm->_useCJKMode) {
                  pos++;
                  curw += _vm->_2byteWidth;
            } else {
                  curw += getCharWidth(chr);
            }
            if (lastspace == -1)
                  continue;
            if (curw > maxwidth) {
                  str[lastspace] = 0xD;
                  curw = 1;
                  pos = lastspace + 1;
                  lastspace = -1;
            }
      }

      setCurID(oldID);
}

#ifdef PALMOS_68K
static byte *englishCharsetDataV2;
static byte *germanCharsetDataV2;
static byte *frenchCharsetDataV2;
static byte *italianCharsetDataV2;
static byte *spanishCharsetDataV2;
#else
// English Zak font
static byte englishCharsetDataV2[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x03, 0x06, 0x0C, 0x18, 0x3E, 0x03, 0x00,
      0x80, 0xC0, 0x60, 0x30, 0x18, 0x7C, 0xC0, 0x00,
      0x00, 0x03, 0x3E, 0x18, 0x0C, 0x06, 0x03, 0x01,
      0x00, 0xC0, 0x7C, 0x18, 0x30, 0x60, 0xC0, 0x80,
      0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
      0x03, 0x03, 0x03, 0x07, 0x07, 0x0F, 0x1F, 0x7F,
      0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0,
      0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07,
      0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18,
      0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18,
      0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00,
      0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xC0, 0xE0, 0x30, 0x18, 0x18,
      0x18, 0x18, 0x30, 0xE0, 0xC0, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x0C, 0x07, 0x03, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
      0x18, 0x3C, 0x66, 0xC3, 0xC3, 0x66, 0x3C, 0x18,
      0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18,
      0x18, 0x66, 0xC3, 0xDB, 0xDB, 0xC3, 0x66, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00,
      0x18, 0x3E, 0x58, 0x3C, 0x1A, 0x7C, 0x18, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x49, 0x00,
      0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00,
      0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00,
      0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00,
      0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
      0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
      0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00,
      0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
      0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00,
      0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E, 0x00,
      0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
      0x06, 0x0E, 0x1E, 0x66, 0x7F, 0x06, 0x06, 0x00,
      0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00,
      0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00,
      0x7E, 0x66, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00,
      0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00,
      0x7C, 0x82, 0xBA, 0xA2, 0xBA, 0x82, 0x7C, 0x00,
      0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00,
      0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00,
      0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
      0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
      0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
      0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
      0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00,
      0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00,
      0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00,
      0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00,
      0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
      0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
      0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00,
      0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
      0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00,
      0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00,
      0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00,
      0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
      0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00,
      0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00,
      0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00,
      0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00,
      0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
      0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00,
      0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
      0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00,
      0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00,
      0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00,
      0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00,
      0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xDB, 0x00,
      0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
      0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
      0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00,
      0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00,
      0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
      0x00, 0x0E, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00,
      0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C,
      0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00,
      0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3C,
      0x00, 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x00,
      0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
      0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00,
      0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
      0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60,
      0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06,
      0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00,
      0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00,
      0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
      0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00,
      0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78,
      0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00,
      0x01, 0x03, 0x06, 0x6C, 0x78, 0x70, 0x60, 0x00,
      0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18,
      0x10, 0x30, 0x70, 0xFF, 0xFF, 0x70, 0x30, 0x10,
      0x08, 0x0C, 0x0E, 0xFF, 0xFF, 0x0E, 0x0C, 0x08,
};

// German Zak font
static byte germanCharsetDataV2[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x03, 0x06, 0x0c, 0x18, 0x3e, 0x03, 0x00,
      0x80, 0xc0, 0x60, 0x30, 0x18, 0x7c, 0xc0, 0x00,
      0x00, 0x03, 0x3e, 0x18, 0x0c, 0x06, 0x03, 0x01,
      0x00, 0xc0, 0x7c, 0x18, 0x30, 0x60, 0xc0, 0x80,
      0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
      0x03, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x7f,
      0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0,
      0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07,
      0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x18,
      0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x18,
      0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00,
      0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x03, 0x07, 0x0c, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xc0, 0xe0, 0x30, 0x18, 0x18,
      0x18, 0x18, 0x30, 0xe0, 0xc0, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x0c, 0x07, 0x03, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x66, 0x3c, 0x18,
      0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18,
      0x18, 0x66, 0xc3, 0xdb, 0xdb, 0xc3, 0x66, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00,
      0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00,
      0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00,
      0x3c, 0x66, 0x3c, 0x38, 0x67, 0x66, 0x3f, 0x00,
      0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00,
      0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00,
      0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
      0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
      0x00, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00,
      0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00,
      0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00,
      0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x0e, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0e, 0x00,
      0x7c, 0x82, 0xba, 0xa2, 0xa2, 0xba, 0x82, 0x7c,
      0x70, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x70, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x00,
      0x78, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0x78, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7e, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00,
      0x66, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00,
      0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00,
      0x63, 0x77, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x00,
      0x66, 0x76, 0x7e, 0x7e, 0x6e, 0x66, 0x66, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x0e, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x00,
      0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00,
      0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x63, 0x63, 0x63, 0x6b, 0x7f, 0x77, 0x63, 0x00,
      0x66, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00,
      0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00,
      0x7e, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x7e, 0x00,
      0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xdb, 0x00,
      0x00, 0x10, 0x30, 0x7f, 0x7f, 0x30, 0x10, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x00, 0x00, 0x3c, 0x60, 0x60, 0x60, 0x3c, 0x00,
      0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x0e, 0x18, 0x3e, 0x18, 0x18, 0x18, 0x00,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x7c,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3c,
      0x00, 0x60, 0x60, 0x6c, 0x78, 0x6c, 0x66, 0x00,
      0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x00, 0x66, 0x7f, 0x7f, 0x6b, 0x63, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x06,
      0x00, 0x00, 0x7c, 0x66, 0x60, 0x60, 0x60, 0x00,
      0x00, 0x00, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x00,
      0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x0e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x00, 0x00, 0x63, 0x6b, 0x7f, 0x3e, 0x36, 0x00,
      0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x0c, 0x78,
      0x00, 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00,
      0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x00,
      0x42, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x1c, 0x36, 0x36, 0x7c, 0x66, 0x66, 0x7c, 0x40,
      0x08, 0x0c, 0x0e, 0xff, 0xff, 0x0e, 0x0c, 0x08,
};

// French Zak font.
static byte frenchCharsetDataV2[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x03, 0x06, 0x0c, 0x18, 0x3e, 0x03, 0x00,
      0x80, 0xc0, 0x60, 0x30, 0x18, 0x7c, 0xc0, 0x00,
      0x00, 0x03, 0x3e, 0x18, 0x0c, 0x06, 0x03, 0x01,
      0x00, 0xc0, 0x7c, 0x18, 0x30, 0x60, 0xc0, 0x80,
      0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
      0x03, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x7f,
      0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0,
      0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07,
      0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x18,
      0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x18,
      0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00,
      0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x03, 0x07, 0x0c, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xc0, 0xe0, 0x30, 0x18, 0x18,
      0x18, 0x18, 0x30, 0xe0, 0xc0, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x0c, 0x07, 0x03, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x66, 0x3c, 0x18,
      0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18,
      0x18, 0x66, 0xc3, 0xdb, 0xdb, 0xc3, 0x66, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00,
      0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00,
      0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00,
      0x3c, 0x66, 0x3c, 0x38, 0x67, 0x66, 0x3f, 0x00,
      0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00,
      0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00,
      0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
      0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
      0x00, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00,
      0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00,
      0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00,
      0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x10, 0x08, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x18, 0x24, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x3c, 0x60, 0x60, 0x3c, 0x18, 0x38,
      0x3c, 0x66, 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x00,
      0x78, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0x78, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7e, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00,
      0x66, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00,
      0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00,
      0x63, 0x77, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x00,
      0x66, 0x76, 0x7e, 0x7e, 0x6e, 0x66, 0x66, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x0e, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x00,
      0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00,
      0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x63, 0x63, 0x63, 0x6b, 0x7f, 0x77, 0x63, 0x00,
      0x66, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00,
      0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00,
      0x7e, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x7e, 0x00,
      0x08, 0x10, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x10, 0x08, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x18, 0x24, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xdb, 0x00,
      0x00, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x00, 0x00, 0x3c, 0x60, 0x60, 0x60, 0x3c, 0x00,
      0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x0e, 0x18, 0x3e, 0x18, 0x18, 0x18, 0x00,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x7c,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3c,
      0x00, 0x60, 0x60, 0x6c, 0x78, 0x6c, 0x66, 0x00,
      0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x00, 0x66, 0x7f, 0x7f, 0x6b, 0x63, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x06,
      0x00, 0x00, 0x7c, 0x66, 0x60, 0x60, 0x60, 0x00,
      0x00, 0x00, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x00,
      0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x0e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x00, 0x00, 0x63, 0x6b, 0x7f, 0x3e, 0x36, 0x00,
      0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x0c, 0x78,
      0x00, 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00,
      0x18, 0x24, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x18, 0x24, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x10, 0x08, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x18, 0x24, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x08, 0x0c, 0x0e, 0xff, 0xff, 0x0e, 0x0c, 0x08,
};

// Italian Zak font.
static byte italianCharsetDataV2[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x03, 0x06, 0x0c, 0x18, 0x3e, 0x03, 0x00,
      0x80, 0xc0, 0x60, 0x30, 0x18, 0x7c, 0xc0, 0x00,
      0x00, 0x03, 0x3e, 0x18, 0x0c, 0x06, 0x03, 0x01,
      0x00, 0xc0, 0x7c, 0x18, 0x30, 0x60, 0xc0, 0x80,
      0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
      0x03, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x7f,
      0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0,
      0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07,
      0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x18,
      0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x18,
      0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00,
      0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x03, 0x07, 0x0c, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xc0, 0xe0, 0x30, 0x18, 0x18,
      0x18, 0x18, 0x30, 0xe0, 0xc0, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x0c, 0x07, 0x03, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x66, 0x3c, 0x18,
      0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18,
      0x18, 0x66, 0xc3, 0xdb, 0xdb, 0xc3, 0x66, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00,
      0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00,
      0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00,
      0x3c, 0x66, 0x3c, 0x38, 0x67, 0x66, 0x3f, 0x00,
      0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00,
      0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00,
      0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
      0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
      0x00, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00,
      0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00,
      0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00,
      0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x10, 0x08, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x08, 0x10, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x10, 0x08, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x00,
      0x78, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0x78, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7e, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00,
      0x66, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00,
      0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00,
      0x63, 0x77, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x00,
      0x66, 0x76, 0x7e, 0x7e, 0x6e, 0x66, 0x66, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x0e, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x00,
      0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00,
      0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x63, 0x63, 0x63, 0x6b, 0x7f, 0x77, 0x63, 0x00,
      0x66, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00,
      0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00,
      0x7e, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x7e, 0x00,
      0x08, 0x10, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x10, 0x08, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x18, 0x24, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xdb, 0x00,
      0x00, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x00, 0x00, 0x3c, 0x60, 0x60, 0x60, 0x3c, 0x00,
      0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x0e, 0x18, 0x3e, 0x18, 0x18, 0x18, 0x00,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x7c,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3c,
      0x00, 0x60, 0x60, 0x6c, 0x78, 0x6c, 0x66, 0x00,
      0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x00, 0x66, 0x7f, 0x7f, 0x6b, 0x63, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x06,
      0x00, 0x00, 0x7c, 0x66, 0x60, 0x60, 0x60, 0x00,
      0x00, 0x00, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x00,
      0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x0e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x00, 0x00, 0x63, 0x6b, 0x7f, 0x3e, 0x36, 0x00,
      0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x0c, 0x78,
      0x00, 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00,
      0x10, 0x08, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x10, 0x08, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x10, 0x08, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x18, 0x24, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x08, 0x0c, 0x0e, 0xff, 0xff, 0x0e, 0x0c, 0x08,
};

// Spanish Zak font.
// FIXME: This is identical to germanCharsetDataV2 it seems?!
static byte spanishCharsetDataV2[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x01, 0x03, 0x06, 0x0c, 0x18, 0x3e, 0x03, 0x00,
      0x80, 0xc0, 0x60, 0x30, 0x18, 0x7c, 0xc0, 0x00,
      0x00, 0x03, 0x3e, 0x18, 0x0c, 0x06, 0x03, 0x01,
      0x00, 0xc0, 0x7c, 0x18, 0x30, 0x60, 0xc0, 0x80,
      0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
      0x03, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x7f,
      0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0,
      0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07,
      0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x18,
      0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x18,
      0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00,
      0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x03, 0x07, 0x0c, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xc0, 0xe0, 0x30, 0x18, 0x18,
      0x18, 0x18, 0x30, 0xe0, 0xc0, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x0c, 0x07, 0x03, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18,
      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x66, 0x3c, 0x18,
      0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18,
      0x18, 0x66, 0xc3, 0xdb, 0xdb, 0xc3, 0x66, 0x18,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00,
      0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00,
      0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00,
      0x3c, 0x66, 0x3c, 0x38, 0x67, 0x66, 0x3f, 0x00,
      0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00,
      0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00,
      0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
      0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
      0x00, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00,
      0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00,
      0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00,
      0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00,
      0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00,
      0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00,
      0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
      0x0e, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0e, 0x00,
      0x7c, 0x82, 0xba, 0xa2, 0xa2, 0xba, 0x82, 0x7c,
      0x70, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x70, 0x00,
      0x3c, 0x66, 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00,
      0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
      0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x00,
      0x78, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0x78, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7e, 0x00,
      0x7e, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00,
      0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00,
      0x66, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00,
      0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7e, 0x00,
      0x63, 0x77, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x00,
      0x66, 0x76, 0x7e, 0x7e, 0x6e, 0x66, 0x66, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x00,
      0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x0e, 0x00,
      0x7c, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x00,
      0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00,
      0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x63, 0x63, 0x63, 0x6b, 0x7f, 0x77, 0x63, 0x00,
      0x66, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00,
      0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00,
      0x7e, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x7e, 0x00,
      0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xdb, 0x00,
      0x00, 0x10, 0x30, 0x7f, 0x7f, 0x30, 0x10, 0x00,
      0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00,
      0x00, 0x00, 0x3c, 0x60, 0x60, 0x60, 0x3c, 0x00,
      0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
      0x00, 0x0e, 0x18, 0x3e, 0x18, 0x18, 0x18, 0x00,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x7c,
      0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3c,
      0x00, 0x60, 0x60, 0x6c, 0x78, 0x6c, 0x66, 0x00,
      0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
      0x00, 0x00, 0x66, 0x7f, 0x7f, 0x6b, 0x63, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x00,
      0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x60,
      0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x06,
      0x00, 0x00, 0x7c, 0x66, 0x60, 0x60, 0x60, 0x00,
      0x00, 0x00, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x00,
      0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x0e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
      0x00, 0x00, 0x63, 0x6b, 0x7f, 0x3e, 0x36, 0x00,
      0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00,
      0x00, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x0c, 0x78,
      0x00, 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00,
      0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x66, 0x18, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x00,
      0x42, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
      0x1c, 0x36, 0x36, 0x7c, 0x66, 0x66, 0x7c, 0x40,
      0x08, 0x0c, 0x0e, 0xff, 0xff, 0x0e, 0x0c, 0x08,
};
#endif

CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
      : CharsetRendererV3(vm) {

      _fontHeight = 8;

      switch (language) {
      case Common::DE_DEU:
            _fontPtr = germanCharsetDataV2;
            break;
      case Common::FR_FRA:
            _fontPtr = frenchCharsetDataV2;
            break;
      case Common::IT_ITA:
            _fontPtr = italianCharsetDataV2;
            break;
      case Common::ES_ESP:
            _fontPtr = spanishCharsetDataV2;
            break;
      default:
            _fontPtr = englishCharsetDataV2;
            break;
      }

#if 0
      // Decompress weird encoding in which the Zak executable contains the font.
      // I leave the code around in case we need to use it again (e.g. we might
      // have to include different fonts for french/spanish/russian/... version
      // of MM / Zak
      //
      int count = 0, len;
      byte b;
      const byte *data = spanishCharsetDataV2;
      const int size = sizeof(spanishCharsetDataV2);
      for (int offset = 0; offset < size; offset++) {
            if (data[offset+1] == 0x00 && data[offset+2] == 0xB2 &&
                  data[offset+5] == 0x00 && data[offset+6] == 0xB0) {
                  b = data[offset+3];
                  len = data[offset+4];
                  while (len--) {
                        printf("0x%02x, ", b);
                        count++;
                        if (count % 8 == 0)
                              printf("\n");
                  }
                  offset += 6;
            } else {
                  printf("0x%02x, ", data[offset]);
                  count++;
                  if (count % 8 == 0)
                        printf("\n");
            }
      }
      printf("\n");
      _vm->_system->quit();
#endif
}

int CharsetRendererV3::getCharWidth(byte chr) {
      if (chr & 0x80 && _vm->_useCJKMode)
            return _vm->_2byteWidth / 2;
      int spacing = 0;

      spacing = *(_widthTable + chr);

      return spacing;
}

void CharsetRendererV3::setColor(byte color)
{
      bool useShadow = false;
      _color = color;

      // FM-TOWNS version of Loom uses old colour method as well
      if ((_vm->_version >= 2) && (_vm->_features & GF_16COLOR || _vm->_gameId == GID_LOOM)) {
            useShadow = ((_color & 0xF0) != 0);
            _color &= 0x0f;
      } else if (_vm->_features & GF_OLD256) {
            useShadow = ((_color & 0x80) != 0);
            _color &= 0x7f;
      } else
            useShadow = false;

      enableShadow(useShadow);

      translateColor();
}

void CharsetRendererCommon::enableShadow(bool enable) {
      if (enable) {
            if (_vm->_platform == Common::kPlatformFMTowns) {
                  _shadowColor = 8;
                  _shadowMode = kFMTOWNSShadowMode;
            } else {
                  _shadowColor = 0;
                  _shadowMode = kNormalShadowMode;
            }
      } else {
            _shadowMode = kNoShadowMode;
      }
}


void CharsetRendererV3::printChar(int chr) {
      // Indy3 / Zak256 / Loom
      int width, height, origWidth, origHeight;
      VirtScreen *vs;
      byte *charPtr, *dst;
      int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;

      checkRange(_vm->_numCharsets - 1, 0, _curId, "Printing with bad charset %d");

      if ((vs = _vm->findVirtScreen(_top)) == NULL)
            return;

      if (chr == '@')
            return;

      if (is2byte) {
            charPtr = _vm->get2byteCharPtr(chr);
            width = _vm->_2byteWidth;
            height = _vm->_2byteHeight;
      } else {
            charPtr = _fontPtr + chr * 8;
//          width = height = 8;
            width = getCharWidth(chr);
            height = 8;
      }

      origWidth = width;
      origHeight = height;

      if (_shadowMode != kNoShadowMode) {
            width++;
            height++;
      }

      if (_firstChar) {
            _str.left = _left;
            _str.top = _top;
            _str.right = _left;
            _str.bottom = _top;
            _firstChar = false;
      }

      int drawTop = _top - vs->topline;

      _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);

      if (!_ignoreCharsetMask) {
            _hasMask = true;
            _textScreenID = vs->number;
      }
      if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
            dst = vs->getPixels(_left, drawTop);
            drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight);
      } else {
            dst = (byte *)_textSurface.pixels + _top * _textSurface.pitch + _left;
            drawBits1(_textSurface, dst, charPtr, drawTop, origWidth, origHeight);
      }

      if (_str.left > _left)
            _str.left = _left;

      _left += origWidth;

      if (_str.right < _left) {
            _str.right = _left;
            if (_shadowMode != kNoShadowMode)
                  _str.right++;
      }

      if (_str.bottom < _top + height)
            _str.bottom = _top + height;
}

void CharsetRendererV3::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
      byte *charPtr, *dst;
      int width, height;
      int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;
      if (is2byte) {
            charPtr = _vm->get2byteCharPtr(chr);
            width = _vm->_2byteWidth;
            height = _vm->_2byteHeight;
      } else {
            charPtr = _fontPtr + chr * 8;
//          width = height = 8;
            width = getCharWidth(chr);
            height = 8;
      }
      dst = (byte *)s.pixels + y * s.pitch + x;
      drawBits1(s, dst, charPtr, y, width, height);
}

void CharsetRenderer::translateColor() {
      // Based on disassembly
      if (_vm->_renderMode == Common::kRenderCGA) {
            static byte CGAtextColorMap[16] = {0,  3, 3, 3, 5, 5, 5,  15,
                                                               15, 3, 3, 3, 5, 5, 15, 15};
            _color = CGAtextColorMap[_color & 0x0f];
      }

      if (_vm->_renderMode == Common::kRenderHercA || _vm->_renderMode == Common::kRenderHercG) {
            static byte HercTextColorMap[16] = {0, 15,  2, 15, 15,  5, 15,  15,
                                                               8, 15, 15, 15, 15, 15, 15, 15};
            _color = HercTextColorMap[_color & 0x0f];
      }
}


void CharsetRendererClassic::printChar(int chr) {
      int width, height, origWidth, origHeight;
      int offsX, offsY;
      VirtScreen *vs;
      const byte *charPtr;
      int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;

      checkRange(_vm->_numCharsets - 1, 1, _curId, "Printing with bad charset %d");

      if ((vs = _vm->findVirtScreen(_top)) == NULL && (vs = _vm->findVirtScreen(_top + getFontHeight())) == NULL)
            return;

      if (chr == '@')
            return;

      translateColor();

      _vm->_charsetColorMap[1] = _color;

      int type = *_fontPtr;
      if (is2byte) {
            enableShadow(true);
            charPtr = _vm->get2byteCharPtr(chr);
            width = _vm->_2byteWidth;
            height = _vm->_2byteHeight;
            offsX = offsY = 0;
      } else {
            uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
            assert(charOffs < 0x10000);
            if (!charOffs)
                  return;
            charPtr = _fontPtr + charOffs;

            width = charPtr[0];
            height = charPtr[1];

            if (_disableOffsX) {
                  offsX = 0;
            } else {
                  offsX = (signed char)charPtr[2];
            }

            offsY = (signed char)charPtr[3];

            charPtr += 4;     // Skip over char header
      }
      origWidth = width;
      origHeight = height;

      if (_shadowMode != kNoShadowMode) {
            width++;
            height++;
      }
      if (_firstChar) {
            _str.left = 0;
            _str.top = 0;
            _str.right = 0;
            _str.bottom = 0;
      }

      _top += offsY;
      _left += offsX;

      if (_left + origWidth > _right + 1 || _left < 0) {
            _left += origWidth;
            _top -= offsY;
            return;
      }

      _disableOffsX = false;

      if (_firstChar) {
            _str.left = _left;
            _str.top = _top;
            _str.right = _left;
            _str.bottom = _top;
            _firstChar = false;
      }

      if (_left < _str.left)
            _str.left = _left;

      if (_top < _str.top)
            _str.top = _top;

      int drawTop = _top - vs->topline;

      _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);

      byte *dstPtr;
      byte *back = NULL;

      if (!_ignoreCharsetMask) {
            _hasMask = true;
            _textScreenID = vs->number;
      }

      if ((_vm->_heversion >= 71 && type >= 8) || (_vm->_heversion >= 90 && type == 0)) {
#ifndef DISABLE_HE
            if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
                  dstPtr = vs->getPixels(0, 0);
            } else {
                  dstPtr = (byte *)_textSurface.pixels;
            }

            if (_blitAlso && vs->hasTwoBuffers) {
                  dstPtr = vs->getBackPixels(0, 0);
            }

            Common::Rect rScreen(vs->w, vs->h);
            if (type >= 8) {
                  byte imagePalette[256];
                  memset(imagePalette, 0, sizeof(imagePalette));
                  memcpy(imagePalette, _vm->_charsetColorMap, 16);
                  Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen, imagePalette);
            } else {
                  Wiz::copyWizImage(dstPtr, charPtr, vs->w, vs->h, _left, _top, origWidth, origHeight, &rScreen);
            }

            if (_blitAlso && vs->hasTwoBuffers) {
                  Common::Rect dst(_left, _top, _left + origWidth, _top + origHeight);
                  _vm->gdi.copyVirtScreenBuffers(dst);
            }
#endif
      } else {
            Graphics::Surface dstSurface;
            Graphics::Surface backSurface;
            if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
                  dstSurface = *vs;
                  dstPtr = vs->getPixels(_left, drawTop);
            } else {
                  dstSurface = _textSurface;
                  dstPtr = (byte *)_textSurface.pixels + (_top - _vm->_screenTop) * _textSurface.pitch + _left;
            }

            if (_blitAlso && vs->hasTwoBuffers) {
                  backSurface = dstSurface;
                  back = dstPtr;
                  dstSurface = *vs;
                  dstPtr = vs->getBackPixels(_left, drawTop);
            }

            if (!_ignoreCharsetMask && vs->hasTwoBuffers) {
                  drawTop = _top - _vm->_screenTop;
            }

            if (is2byte) {
                  drawBits1(dstSurface, dstPtr, charPtr, drawTop, origWidth, origHeight);
            } else {
                  drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight);
            }

            if (_blitAlso && vs->hasTwoBuffers) {
                  // FIXME: Revisiting this code, I think the _blitAlso mode is likely broken
                  // right now -- we are copying stuff from "dstPtr" to "back", but "dstPtr" really
                  // only conatains charset data...
                  // One way to fix this: don't copy etc.; rather simply render the char twice,
                  // once to each of the two buffers. That should hypothetically yield
                  // identical results, though I didn't try it and right now I don't know
                  // any spots where I can test this...
                  if (!_ignoreCharsetMask)
                        warning("This might be broken -- please report where you encountered this to Fingolfin");

                  // Perform some clipping
                  int w = MIN(width, dstSurface.w - _left);
                  int h = MIN(height, dstSurface.h - drawTop);
                  if (_left < 0) {
                        w += _left;
                        back -= _left;
                        dstPtr -= _left;
                  }
                  if (drawTop < 0) {
                        h += drawTop;
                        back -= drawTop * backSurface.pitch;
                        dstPtr -= drawTop * dstSurface.pitch;
                  }

                  // Blit the image data
                  if (w > 0) {
                        while (h-- > 0) {
                              memcpy(back, dstPtr, w);
                              back += backSurface.pitch;
                              dstPtr += dstSurface.pitch;
                        }
                  }
            }
      }

      _left += origWidth;

      if (_str.right < _left) {
            _str.right = _left;
            if (_shadowMode != kNoShadowMode)
                  _str.right++;
      }

      if (_str.bottom < _top + height)
            _str.bottom = _top + height;

      _top -= offsY;
}

void CharsetRendererClassic::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
      const byte *charPtr;
      byte *dst;
      int width, height;
      int is2byte = (chr >= 0x80 && _vm->_useCJKMode) ? 1 : 0;

      if (is2byte) {
            enableShadow(true);
            charPtr = _vm->get2byteCharPtr(chr);
            width = _vm->_2byteWidth;
            height = _vm->_2byteHeight;
      } else {
            uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
            assert(charOffs < 0x10000);
            if (!charOffs)
                  return;
            charPtr = _fontPtr + charOffs;

            width = charPtr[0];
            height = charPtr[1];

            charPtr += 4;     // Skip over char header
      }

      dst = (byte *)s.pixels + y * s.pitch + x;

      if (is2byte) {
            drawBits1(s, dst, charPtr, y, width, height);
      } else {
            drawBitsN(s, dst, charPtr, *_fontPtr, y, width, height);
      }
}

void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
      int y, x;
      int color;
      byte numbits, bits;

      assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
      bits = *src++;
      numbits = 8;

      for (y = 0; y < height && y + drawTop < s.h; y++) {
            for (x = 0; x < width; x++) {
                  color = (bits >> (8 - bpp)) & 0xFF;

                  if (color && y + drawTop >= 0) {
                        *dst = _vm->_charsetColorMap[color];
                  }
                  dst++;
                  bits <<= bpp;
                  numbits -= bpp;
                  if (numbits == 0) {
                        bits = *src++;
                        numbits = 8;
                  }
            }
            dst += s.pitch - width;
      }
}

void CharsetRendererCommon::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height) {
      int y, x;
      byte bits = 0;

      for (y = 0; y < height && y + drawTop < s.h; y++) {
            for (x = 0; x < width; x++) {
                  if ((x % 8) == 0)
                        bits = *src++;
                  if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) {
                        if (_shadowMode != kNoShadowMode) {
                              *(dst + 1) = _shadowColor;
                              *(dst + s.pitch) = _shadowColor;
                              if (_shadowMode != kFMTOWNSShadowMode)
                                    *(dst + s.pitch + 1) = _shadowColor;
                        }
                        *dst = _color;
                  }
                  dst++;
            }

            dst += s.pitch - width;
      }
}

#ifndef DISABLE_SCUMM_7_8
CharsetRendererNut::CharsetRendererNut(ScummEngine *vm)
       : CharsetRenderer(vm) {
      _current = 0;

      for (int i = 0; i < 5; i++) {
            char fontname[256];
            if ((_vm->_gameId == GID_CMI) && (_vm->_features & GF_DEMO) && (i == 4))
                  break;
            sprintf(fontname, "font%d.nut", i);
            _fr[i] = new NutRenderer(_vm);
            if (!(_fr[i]->loadFont(fontname))) {
                  delete _fr[i];
                  _fr[i] = NULL;
            }
      }
}

CharsetRendererNut::~CharsetRendererNut() {
      for (int i = 0; i < 5; i++) {
            if ((_vm->_gameId == GID_CMI) && (_vm->_features & GF_DEMO) && (i == 4))
                  break;
            delete _fr[i];
      }
}

void CharsetRendererNut::setCurID(byte id) {
      assert(id < 5);
      _curId = id;
      _current = _fr[id];
      assert(_current);
}

int CharsetRendererNut::getCharHeight(byte chr) {
      assert(_current);
      return _current->getCharHeight(chr);
}

int CharsetRendererNut::getCharWidth(byte chr) {
      assert(_current);
      return _current->getCharWidth(chr);
}

int CharsetRendererNut::getFontHeight() {
      // FIXME / TODO: how to implement this properly???
      assert(_current);
      return _current->getCharHeight('|');
}

void CharsetRendererNut::printChar(int chr) {
      Common::Rect shadow;

      assert(_current);
      if (chr == '@')
            return;

      shadow.left = _left - 1;
      shadow.top = _top - 1;

      // Note that the character is drawn with a shadow, so it is slightly
      // larger than the advertised dimensions. See drawShadowChar() for
      // details.

      if (_firstChar) {
            _str.left = (shadow.left >= 0) ? shadow.left : 0;
            _str.top = (shadow.top >= 0) ? shadow.top : 0;
            _str.right = _str.left;
            _str.bottom = _str.top;
            _firstChar = false;
      }

      int width = _current->getCharWidth(chr);
      int height = _current->getCharHeight(chr);

      if (chr >= 256 && _vm->_useCJKMode)
            width = _vm->_2byteWidth;

      shadow.right = _left + width + 2;
      shadow.bottom = _top + height + 2;

      Graphics::Surface s;
      if (!_ignoreCharsetMask) {
            _hasMask = true;
            _textScreenID = kMainVirtScreen;
      }

      int drawTop = _top;
      if (_ignoreCharsetMask) {
            VirtScreen *vs = &_vm->virtscr[kMainVirtScreen];
            s = *vs;
            s.pixels = vs->getPixels(0, 0);
      } else {
            s = _textSurface;
            drawTop -= _vm->_screenTop;
      }

      _current->drawShadowChar(s, chr, _left, drawTop, _color, _curId != 3);
      _vm->markRectAsDirty(kMainVirtScreen, shadow);

      if (_str.left > _left)
            _str.left = _left;

      _left += width;

      if (_str.right < shadow.right)
            _str.right = shadow.right;

      if (_str.bottom < shadow.bottom)
            _str.bottom = shadow.bottom;
}
#endif

void CharsetRendererNES::printChar(int chr) {
      int width, height, origWidth, origHeight;
      VirtScreen *vs;
      byte *charPtr, *dst;

      // Init it here each time since it is cheap and fixes bug with
      // charset after game load
      _trTable = _vm->getResourceAddress(rtCostume, 77) + 2;

      // HACK: how to set it properly?
      if (_top == 0)
            _top = 16;

      if ((vs = _vm->findVirtScreen(_top)) == NULL)
            return;

      if (chr == '@')
            return;

      charPtr = _vm->_NESPatTable[1] + _trTable[chr - 32] * 16;
      width = getCharWidth(chr);
      height = 8;

      origWidth = width;
      origHeight = height;

      if (_firstChar) {
            _str.left = _left;
            _str.top = _top;
            _str.right = _left;
            _str.bottom = _top;
            _firstChar = false;
      }

      int drawTop = _top - vs->topline;

      _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);

      if (!_ignoreCharsetMask) {
            _hasMask = true;
            _textScreenID = vs->number;
      }

      if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
            dst = vs->getPixels(_left, drawTop);
            drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight);
      } else {
            dst = (byte *)_textSurface.pixels + _top * _textSurface.pitch + _left;
            drawBits1(_textSurface, dst, charPtr, drawTop, origWidth, origHeight);
      }

      if (_str.left > _left)
            _str.left = _left;

      _left += origWidth;

      if (_str.right < _left) {
            _str.right = _left;
            if (_shadowMode != kNoShadowMode)
                  _str.right++;
      }

      if (_str.bottom < _top + height)
            _str.bottom = _top + height;
}

void CharsetRendererNES::drawChar(int chr, const Graphics::Surface &s, int x, int y) {
      byte *charPtr, *dst;
      int width, height;

      if (!_trTable)
            _trTable = _vm->getResourceAddress(rtCostume, 77) + 2;

      charPtr = _vm->_NESPatTable[1] + _trTable[chr - 32] * 16;
      width = getCharWidth(chr);
      height = 8;

      dst = (byte *)s.pixels + y * s.pitch + x;
      drawBits1(s, dst, charPtr, y, width, height);
}

void CharsetRendererNES::drawBits1(const Graphics::Surface &s, byte *dst, const byte *src, int drawTop, int width, int height) {
      for (int i = 0; i < 8; i++) {
            byte c0 = src[i];
            byte c1 = src[i + 8];
            for (int j = 0; j < 8; j++)
                  dst[j] = _vm->_NESPalette[0][((c0 >> (7 - j)) & 1) | (((c1 >> (7 - j)) & 1) << 1) |
                  (_color ? 12 : 8)];
            dst += s.pitch;
      }
}

} // End of namespace Scumm

#ifdef PALMOS_68K
#include "scumm_globals.h"

_GINIT(Charset)
_GSETPTR(Scumm::germanCharsetDataV2, GBVARS_GERMANCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM)
_GSETPTR(Scumm::frenchCharsetDataV2, GBVARS_FRENCHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM)
_GSETPTR(Scumm::englishCharsetDataV2, GBVARS_ENGLISHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM)
_GSETPTR(Scumm::italianCharsetDataV2, GBVARS_ITALIANCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM)
_GSETPTR(Scumm::spanishCharsetDataV2, GBVARS_SPANISHCHARSETDATAV2_INDEX, byte, GBVARS_SCUMM)
_GEND

_GRELEASE(Charset)
_GRELEASEPTR(GBVARS_GERMANCHARSETDATAV2_INDEX, GBVARS_SCUMM)
_GRELEASEPTR(GBVARS_FRENCHCHARSETDATAV2_INDEX, GBVARS_SCUMM)
_GRELEASEPTR(GBVARS_ENGLISHCHARSETDATAV2_INDEX, GBVARS_SCUMM)
_GRELEASEPTR(GBVARS_ITALIANCHARSETDATAV2_INDEX, GBVARS_SCUMM)
_GRELEASEPTR(GBVARS_SPANISHCHARSETDATAV2_INDEX, GBVARS_SCUMM)
_GEND

#endif

Generated by  Doxygen 1.6.0   Back to index