// $Id: Printer.cc 6136 2007-03-03 09:43:34Z m9710797 $ #include "Printer.hh" #include "ScreenShotSaver.hh" #include "FileOperations.hh" #include "FloatSetting.hh" #include "MSXMotherBoard.hh" #include "MSXCliComm.hh" #include "Math.hh" #include #include #include #include #include using std::max; using std::min; using std::string; namespace openmsx { class Paper { public: Paper(unsigned x, unsigned y); ~Paper(); std::string save() const; void setDotSize(double sizeX, double sizeY); void plot(double x, double y); private: byte& dot(unsigned x, unsigned y); byte* buf; unsigned sizeX; unsigned sizeY; double radiusX; double radiusY; int radius16; std::vector table; }; PrinterCore::PrinterCore() : toPrint(0), prevStrobe(true) { } PrinterCore::~PrinterCore() { } bool PrinterCore::getStatus(const EmuTime& /*time*/) { return false; // false = low = ready } void PrinterCore::setStrobe(bool strobe, const EmuTime& /*time*/) { if (!strobe && prevStrobe) { // falling edge write(toPrint); } prevStrobe = strobe; } void PrinterCore::writeData(byte data, const EmuTime& /*time*/) { toPrint = data; } void PrinterCore::plugHelper(Connector& /*connector*/, const EmuTime& /*time*/) { // nothing } void PrinterCore::unplugHelper(const EmuTime& /*time*/) { forceFormFeed(); } /* // class RawPrinter RawPrinter::RawPrinter() { Properties* properties = propGetGlobalProperties(); hFile = CreateFile(properties->ports.Lpt.portName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); if (hFile == INVALID_HANDLE_VALUE) { throw MSXException(); } } void RawPrinter::~RawPrinter() { CloseHandle(hFile); } void RawPrinter::write(byte value) { unsigned dwWritten; WriteFile(hFile, &value, 1, &dwWritten, NULL); } void RawPrinter::forceFormFeed() { } */ // class ImagePrinter ImagePrinter::ImagePrinter(MSXMotherBoard& motherBoard_) : motherBoard(motherBoard_) { MSXMotherBoard::SharedStuff& info = motherBoard.getSharedStuff("print-resolution"); if (info.counter == 0) { assert(info.stuff == NULL); info.stuff = new FloatSetting( motherBoard.getCommandController(), "print-resolution", "resolution of the ouput image of emulated dot matrix printer in DPI", 300, 150, 1200); } ++info.counter; dpiSetting = reinterpret_cast(info.stuff); letterQuality = false; bold = false; proportional = false; italic = false; superscript = false; subscript = false; doubleWidth = false; underline = false; doubleStrike = false; escSequence = false; alternateChar = false; detectPaperOut = false; japanese = false; normalAfterLine = false; ninePinGraphics = false; leftToRight = false; elite = false; compressed = false; noHighEscapeCodes = false; eightBit = 0; perforationSkip = 0; remainingCommandBytes = 0; sizeEscPos = 0; sizeRemainingDataBytes = 0; ramLoadOffset = 0; ramLoadEnd = 0; countryCode = CC_USA; printAreaTop = -1.0; printAreaBottom = 0.0; } ImagePrinter::~ImagePrinter() { flushEmulatedPrinter(); MSXMotherBoard::SharedStuff& info = motherBoard.getSharedStuff("print-resolution"); assert(info.counter); assert(dpiSetting); assert(dpiSetting == info.stuff); --info.counter; if (info.counter == 0) { delete dpiSetting; info.stuff = NULL; } } void ImagePrinter::write(byte data) { if (ramLoadOffset < ramLoadEnd) { fontInfo.ram[ramLoadOffset++] = data; } else if (sizeRemainingDataBytes) { if (eightBit == 0) { data &= 0x80; } else if (eightBit == 1) { data |= 0x80; } printGraphicByte(data); sizeRemainingDataBytes--; } else if (escSequence) { escSequence = false; memset(&(abEscSeq), 0, sizeof(abEscSeq)); *(abEscSeq) = data; sizeEscPos = 1; remainingCommandBytes = calcEscSequenceLength(data); if (!remainingCommandBytes) { processEscSequence(); } } else if (remainingCommandBytes) { abEscSeq[sizeEscPos++] = data; if (!--remainingCommandBytes) { processEscSequence(); } } else { processCharacter(data); } } void ImagePrinter::forceFormFeed() { flushEmulatedPrinter(); } void ImagePrinter::resetEmulatedPrinter() { resetSettings(); pageHeight = pageTop + lines * lineFeed; hpos = leftBorder; vpos = pageTop; } void ImagePrinter::plot9Dots(double x, double y, unsigned pattern) { for (int i = 0; i < 9; ++i) { if (pattern & (1 << i)) { paper->plot(x, y + (8 - i) * pixelSizeY); } } } void ImagePrinter::printGraphicByte(byte data) { ensurePrintPage(); double destY = vpos * pixelSizeY; double destHeight = pixelSizeY * 9.0; // Print Data to high 8 bits unsigned charBits = (graphicsHiLo ? Math::reverseByte(data) : data) << 1; printAreaTop = min(printAreaTop, destY); printAreaBottom = max(printAreaBottom, destY + destHeight); // Print bit-mask plot9Dots(hpos * pixelSizeX, destY, charBits); // Move print-position... seekPrinterHeadRelative(1.0 / graphDensity); } void ImagePrinter::seekPrinterHeadRelative(double offset) { hpos += offset; if ((unsigned)hpos > rightBorder) { hpos = leftBorder; vpos += lineFeed; if (vpos >= pageHeight) { doubleWidth ^= normalAfterLine; flushEmulatedPrinter(); } } } void ImagePrinter::ensurePrintPage() { if (!paper.get()) { // A4 paper format (210mm x 297mm) at 300dpi // TODO make this configurable double dpi = dpiSetting->getValue(); unsigned paperSizeX = static_cast((210 / 25.4) * dpi); unsigned paperSizeY = static_cast((297 / 25.4) * dpi); paper.reset(new Paper(paperSizeX, paperSizeY)); unsigned dotsX, dotsY; getNumberOfDots(dotsX, dotsY); pixelSizeX = (double)paperSizeX / dotsX; pixelSizeY = (double)paperSizeY / dotsY; paper->setDotSize(pixelSizeX, pixelSizeY); } } void ImagePrinter::flushEmulatedPrinter() { if (paper.get()) { if (printAreaBottom > printAreaTop) { try { string filename = paper->save(); motherBoard.getMSXCliComm().printInfo( "Printed to " + filename); } catch (MSXException& e) { motherBoard.getMSXCliComm().printWarning( "Failed to print: " + e.getMessage()); } printAreaTop = -1.0; printAreaBottom = 0.0; } paper.reset(); } hpos = leftBorder; vpos = pageTop; } static unsigned compress9(unsigned a) { unsigned result = 0; for (int i = 0; i < 9; ++i) { if (a & (1 << i)) { result |= 1 << (i / 2); } } return result; } void ImagePrinter::printVisibleCharacter(byte data) { ensurePrintPage(); double iYPos = 0; byte* charBitmap = (fontInfo.useRam ? fontInfo.ram : fontInfo.rom) + fontInfo.charWidth * data; byte attribute = charBitmap[0]; unsigned start = (attribute >> 4) & 0x07; unsigned end = attribute & 0x0f; unsigned topBits = attribute >> 7; bool script = superscript || subscript; if (!proportional) { start = 0; // Fixed width font end = fontInfo.charWidth - 1; } if (subscript) { iYPos /= 2.0; iYPos += pixelSizeY * 4.5; } if (script) { iYPos -= pixelSizeY * 4.5; } double hPos = hpos; double headRelative = (doubleWidth ? 2 : 1) * fontInfo.pixelDelta / fontDensity; double destY = vpos * pixelSizeY + iYPos; double destHeight = pixelSizeY * 9.0; double dblStrikeOffset = doubleStrike ? (pixelSizeY / 2.5) : 0.0; printAreaTop = min(printAreaTop, destY); printAreaBottom = max(printAreaBottom, destY + destHeight + dblStrikeOffset); for (unsigned i = start; i < end; ++i) { unsigned charBits = (unsigned)charBitmap[i + 1] << topBits; if (underline) { charBits |= 2; } if (script) { charBits = compress9(charBits); } for (int d = 0; d <= doubleWidth; d++) { for (int b = 0; b <= bold; ++b) { for (int y = 0; y <= doubleStrike; ++y) { double destX = (hPos + (d + b / 2.0) / fontDensity) * pixelSizeX; plot9Dots(destX, destY + y * dblStrikeOffset, charBits); } } } hPos += headRelative; } seekPrinterHeadRelative((1 + end - start) * headRelative); } // class ImagePrinterMSX // MSX-Font taken from NMS8250 BIOS ROM static const byte MSXFontRaw[256 * 8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C, // 1 0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x66, 0x3C, // 2 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, // 3 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, // 4 0x10, 0x38, 0x54, 0xFE, 0x54, 0x10, 0x38, 0x00, // 5 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x10, 0x38, 0x00, // 6 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, // 7 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, // 8 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, // 9 0xC7, 0xBB, 0x7D, 0x7D, 0x7D, 0xBB, 0xC7, 0xFF, // 10 0x0F, 0x03, 0x05, 0x79, 0x88, 0x88, 0x88, 0x70, // 11 0x38, 0x44, 0x44, 0x44, 0x38, 0x10, 0x7C, 0x10, // 12 0x30, 0x28, 0x24, 0x24, 0x28, 0x20, 0xE0, 0xC0, // 13 0x3C, 0x24, 0x3C, 0x24, 0x24, 0xE4, 0xDC, 0x18, // 14 0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 15 0x10, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x10, 0x10, // 16 0x10, 0x10, 0x10, 0xFF, 0x00, 0x00, 0x00, 0x00, // 17 0x00, 0x00, 0x00, 0xFF, 0x10, 0x10, 0x10, 0x10, // 18 0x10, 0x10, 0x10, 0xF0, 0x10, 0x10, 0x10, 0x10, // 19 0x10, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, // 20 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, // 21 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 22 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, // 23 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, // 24 0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x10, 0x10, // 25 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, // 26 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, // 27 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, // 28 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, // 29 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, // 30 0x00, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x00, 0x00, // 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20, 0x00, // 33 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // 34 0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, // 35 0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00, // 36 0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18, 0x00, // 37 0x40, 0xA0, 0x40, 0xA8, 0x90, 0x98, 0x60, 0x00, // 38 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // 39 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, // 40 0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00, // 41 0x20, 0xA8, 0x70, 0x20, 0x70, 0xA8, 0x20, 0x00, // 42 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, // 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, // 44 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, // 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, // 46 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, // 47 0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70, 0x00, // 48 0x20, 0x60, 0xA0, 0x20, 0x20, 0x20, 0xF8, 0x00, // 49 0x70, 0x88, 0x08, 0x10, 0x60, 0x80, 0xF8, 0x00, // 50 0x70, 0x88, 0x08, 0x30, 0x08, 0x88, 0x70, 0x00, // 51 0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00, // 52 0xF8, 0x80, 0xE0, 0x10, 0x08, 0x10, 0xE0, 0x00, // 53 0x30, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70, 0x00, // 54 0xF8, 0x88, 0x10, 0x20, 0x20, 0x20, 0x20, 0x00, // 55 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, // 56 0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0x60, 0x00, // 57 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, // 58 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x40, // 59 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, // 60 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, // 61 0xC0, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC0, 0x00, // 62 0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00, // 63 0x70, 0x88, 0x08, 0x68, 0xA8, 0xA8, 0x70, 0x00, // 64 0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, // 65 0xF0, 0x48, 0x48, 0x70, 0x48, 0x48, 0xF0, 0x00, // 66 0x30, 0x48, 0x80, 0x80, 0x80, 0x48, 0x30, 0x00, // 67 0xE0, 0x50, 0x48, 0x48, 0x48, 0x50, 0xE0, 0x00, // 68 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, // 69 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, // 70 0x70, 0x88, 0x80, 0xB8, 0x88, 0x88, 0x70, 0x00, // 71 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, // 72 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, // 73 0x38, 0x10, 0x10, 0x10, 0x90, 0x90, 0x60, 0x00, // 74 0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, // 75 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, // 76 0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88, 0x00, // 77 0x88, 0xC8, 0xC8, 0xA8, 0x98, 0x98, 0x88, 0x00, // 78 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 79 0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, // 80 0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68, 0x00, // 81 0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00, // 82 0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00, // 83 0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, // 84 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 85 0x88, 0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, // 86 0x88, 0x88, 0x88, 0xA8, 0xA8, 0xD8, 0x88, 0x00, // 87 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, // 88 0x88, 0x88, 0x88, 0x70, 0x20, 0x20, 0x20, 0x00, // 89 0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, // 90 0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x00, // 91 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, // 92 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, // 93 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, // 94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, // 95 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 97 0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00, // 98 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, // 99 0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00, // 100 0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 101 0x10, 0x28, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x00, // 102 0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x70, // 103 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x88, 0x00, // 104 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, // 105 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x90, 0x60, // 106 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, // 107 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, // 108 0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00, // 109 0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, // 110 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, // 111 0x00, 0x00, 0xB0, 0xC8, 0xC8, 0xB0, 0x80, 0x80, // 112 0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x08, // 113 0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00, // 114 0x00, 0x00, 0x78, 0x80, 0xF0, 0x08, 0xF0, 0x00, // 115 0x40, 0x40, 0xF0, 0x40, 0x40, 0x48, 0x30, 0x00, // 116 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x68, 0x00, // 117 0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, // 118 0x00, 0x00, 0x88, 0xA8, 0xA8, 0xA8, 0x50, 0x00, // 119 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, // 120 0x00, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x70, // 121 0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, // 122 0x18, 0x20, 0x20, 0x40, 0x20, 0x20, 0x18, 0x00, // 123 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00, // 124 0xC0, 0x20, 0x20, 0x10, 0x20, 0x20, 0xC0, 0x00, // 125 0x40, 0xA8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 126 0x00, 0x00, 0x20, 0x50, 0xF8, 0x00, 0x00, 0x00, // 127 0x70, 0x88, 0x80, 0x80, 0x88, 0x70, 0x20, 0x60, // 128 0x90, 0x00, 0x00, 0x90, 0x90, 0x90, 0x68, 0x00, // 129 0x10, 0x20, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 130 0x20, 0x50, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 131 0x48, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 132 0x20, 0x10, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 133 0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 134 0x00, 0x70, 0x80, 0x80, 0x80, 0x70, 0x10, 0x60, // 135 0x20, 0x50, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 136 0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 137 0x20, 0x10, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, // 138 0x50, 0x00, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 139 0x20, 0x50, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 140 0x40, 0x20, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 141 0x50, 0x00, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 142 0x20, 0x00, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 143 0x10, 0x20, 0xF8, 0x80, 0xF0, 0x80, 0xF8, 0x00, // 144 0x00, 0x00, 0x6C, 0x12, 0x7E, 0x90, 0x6E, 0x00, // 145 0x3E, 0x50, 0x90, 0x9C, 0xF0, 0x90, 0x9E, 0x00, // 146 0x60, 0x90, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 147 0x90, 0x00, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 148 0x40, 0x20, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 149 0x40, 0xA0, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 150 0x40, 0x20, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 151 0x90, 0x00, 0x90, 0x90, 0xB0, 0x50, 0x10, 0xE0, // 152 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, // 153 0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, // 154 0x20, 0x20, 0x78, 0x80, 0x80, 0x78, 0x20, 0x20, // 155 0x18, 0x24, 0x20, 0xF8, 0x20, 0xE2, 0x5C, 0x00, // 156 0x88, 0x50, 0x20, 0xF8, 0x20, 0xF8, 0x20, 0x00, // 157 0xC0, 0xA0, 0xA0, 0xC8, 0x9C, 0x88, 0x88, 0x8C, // 158 0x18, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x40, // 159 0x10, 0x20, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 160 0x10, 0x20, 0x00, 0x60, 0x20, 0x20, 0x70, 0x00, // 161 0x20, 0x40, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 162 0x20, 0x40, 0x00, 0x90, 0x90, 0x90, 0x68, 0x00, // 163 0x50, 0xA0, 0x00, 0xA0, 0xD0, 0x90, 0x90, 0x00, // 164 0x28, 0x50, 0x00, 0xC8, 0xA8, 0x98, 0x88, 0x00, // 165 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0xF8, // 166 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00, 0xF0, // 167 0x20, 0x00, 0x20, 0x40, 0x80, 0x88, 0x70, 0x00, // 168 0x00, 0x00, 0x00, 0xF8, 0x80, 0x80, 0x00, 0x00, // 169 0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x00, 0x00, // 170 0x84, 0x88, 0x90, 0xA8, 0x54, 0x84, 0x08, 0x1C, // 171 0x84, 0x88, 0x90, 0xA8, 0x58, 0xA8, 0x3C, 0x08, // 172 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, // 173 0x00, 0x00, 0x24, 0x48, 0x90, 0x48, 0x24, 0x00, // 174 0x00, 0x00, 0x90, 0x48, 0x24, 0x48, 0x90, 0x00, // 175 0x28, 0x50, 0x20, 0x50, 0x88, 0xF8, 0x88, 0x00, // 176 0x28, 0x50, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, // 177 0x28, 0x50, 0x00, 0x70, 0x20, 0x20, 0x70, 0x00, // 178 0x28, 0x50, 0x00, 0x20, 0x20, 0x20, 0x70, 0x00, // 179 0x28, 0x50, 0x00, 0x70, 0x88, 0x88, 0x70, 0x00, // 180 0x50, 0xA0, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, // 181 0x28, 0x50, 0x00, 0x88, 0x88, 0x88, 0x70, 0x00, // 182 0x50, 0xA0, 0x00, 0xA0, 0xA0, 0xA0, 0x50, 0x00, // 183 0xFC, 0x48, 0x48, 0x48, 0xE8, 0x08, 0x50, 0x20, // 184 0x00, 0x50, 0x00, 0x50, 0x50, 0x50, 0x10, 0x20, // 185 0xC0, 0x44, 0xC8, 0x54, 0xEC, 0x54, 0x9E, 0x04, // 186 0x10, 0xA8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // 187 0x00, 0x20, 0x50, 0x88, 0x50, 0x20, 0x00, 0x00, // 188 0x88, 0x10, 0x20, 0x40, 0x80, 0x28, 0x00, 0x00, // 189 0x7C, 0xA8, 0xA8, 0x68, 0x28, 0x28, 0x28, 0x00, // 190 0x38, 0x40, 0x30, 0x48, 0x48, 0x30, 0x08, 0x70, // 191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 192 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, // 193 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 194 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 195 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, // 196 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, // 197 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 198 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, // 199 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, // 200 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 201 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 202 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88, // 203 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, // 204 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, // 205 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, // 206 0x80, 0xC0, 0xE0, 0xF0, 0xE0, 0xC0, 0x80, 0x00, // 207 0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00, // 208 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x3C, 0x7E, 0xFF, // 209 0x81, 0xC3, 0xE7, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, // 210 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, // 211 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, // 212 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, // 213 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, // 214 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, // 215 0x00, 0x20, 0x20, 0x50, 0x50, 0x88, 0xF8, 0x00, // 216 0x20, 0x20, 0x70, 0x20, 0x70, 0x20, 0x20, 0x00, // 217 0x00, 0x00, 0x00, 0x50, 0x88, 0xA8, 0x50, 0x00, // 218 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 219 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // 220 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 221 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 222 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // 223 0x00, 0x00, 0x68, 0x90, 0x90, 0x90, 0x68, 0x00, // 224 0x30, 0x48, 0x48, 0x70, 0x48, 0x48, 0x70, 0xC0, // 225 0xF8, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, // 226 0xF8, 0x50, 0x50, 0x50, 0x50, 0x50, 0x98, 0x00, // 227 0xF8, 0x88, 0x40, 0x20, 0x40, 0x88, 0xF8, 0x00, // 228 0x00, 0x00, 0x78, 0x90, 0x90, 0x90, 0x60, 0x00, // 229 0x00, 0x50, 0x50, 0x50, 0x50, 0x68, 0x80, 0x80, // 230 0x00, 0x50, 0xA0, 0x20, 0x20, 0x20, 0x20, 0x00, // 231 0xF8, 0x20, 0x70, 0xA8, 0xA8, 0x70, 0x20, 0xF8, // 232 0x20, 0x50, 0x88, 0xF8, 0x88, 0x50, 0x20, 0x00, // 233 0x70, 0x88, 0x88, 0x88, 0x50, 0x50, 0xD8, 0x00, // 234 0x30, 0x40, 0x40, 0x20, 0x50, 0x50, 0x50, 0x20, // 235 0x00, 0x00, 0x00, 0x50, 0xA8, 0xA8, 0x50, 0x00, // 236 0x08, 0x70, 0xA8, 0xA8, 0xA8, 0x70, 0x80, 0x00, // 237 0x38, 0x40, 0x80, 0xF8, 0x80, 0x40, 0x38, 0x00, // 238 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, // 239 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, // 240 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0xF8, 0x00, // 241 0xC0, 0x30, 0x08, 0x30, 0xC0, 0x00, 0xF8, 0x00, // 242 0x18, 0x60, 0x80, 0x60, 0x18, 0x00, 0xF8, 0x00, // 243 0x10, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // 244 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA0, 0x40, // 245 0x00, 0x20, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x00, // 246 0x00, 0x50, 0xA0, 0x00, 0x50, 0xA0, 0x00, 0x00, // 247 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, // 248 0x00, 0x30, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, // 249 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, // 250 0x3E, 0x20, 0x20, 0x20, 0xA0, 0x60, 0x20, 0x00, // 251 0xA0, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, // 252 0x40, 0xA0, 0x20, 0x40, 0xE0, 0x00, 0x00, 0x00, // 253 0x00, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, // 254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 255 }; static byte MSXFont[256 * 9]; ImagePrinterMSX::ImagePrinterMSX(MSXMotherBoard& motherBoard) : ImagePrinter(motherBoard) { graphicsHiLo = true; msxPrnSetFont(MSXFontRaw); resetEmulatedPrinter(); } const string& ImagePrinterMSX::getName() const { static const string name("msx-printer"); return name; } const string& ImagePrinterMSX::getDescription() const { // TODO which printer type static const string desc( "Emulate MSX printer, prints to image."); return desc; } void ImagePrinterMSX::msxPrnSetFont(const byte* msxBits) { // Convert MSX printer font to Epson printer font byte* font = MSXFont; for (int i = 0; i < 256; ++i) { byte oneBits = 0; int start = -1; int end = 0; // Rotate MSX character for (int j = 0; j < 8; ++j) { byte charBits = 0; for (int k = 0; k < 8; ++k) { charBits |= ((msxBits[7 - k] >> (7 - j)) & 1) << k; } oneBits |= charBits; if (oneBits != 0 && start < 0) start = j; if (charBits != 0) end = j; font[j + 1] = charBits; } end = end + 1; if (start < 0 || start >= 7) start = 0; if (end == 1) end = 5; if (end >= 7) end = 7; font[0] = (start << 4) | end; font += 9; msxBits += 8; } } void ImagePrinterMSX::getNumberOfDots(unsigned& dotsX, unsigned& dotsY) { dotsX = 825; dotsY = 825; } void ImagePrinterMSX::resetSettings() { lineFeed = 12.0; leftBorder = 48; rightBorder = 800; graphDensity = 1.0; fontDensity = 1.0; pageTop = 48; lines = 72; fontWidth = 8; eightBit = -1; memcpy(fontInfo.rom, MSXFont, sizeof(fontInfo.rom)); fontInfo.charWidth = 9; fontInfo.pixelDelta = 1.0; fontInfo.useRam = false; } unsigned ImagePrinterMSX::calcEscSequenceLength(byte character) { switch (character) { case 'C': return 1; case 'T': case 'Z': return 2; case 'O': case '\\': case 'L': case '/': return 3; case 'S': return 4; case 'G': return 7; default: return 0; } } unsigned ImagePrinterMSX::parseNumber(unsigned sizeStart, unsigned sizeChars) { unsigned Value = 0; while (sizeChars--) { Value = Value * 10; byte data = abEscSeq[sizeStart++]; if (data >= '0' && data <= '9') { Value += (unsigned)(data - '0'); } } return Value; } void ImagePrinterMSX::processEscSequence() { switch (abEscSeq[0]) { case 'N': proportional = false; fontDensity = 1.0; break; case 'E': proportional = false; fontDensity = 1.40; break; case 'Q': proportional = false; fontDensity = 1.72; break; case 'P': proportional = true; fontDensity = 0.90; break; case '!': letterQuality = true; break; case '\"': letterQuality = false; break; case 'C': switch (abEscSeq[1]) { case 'D': doubleStrike = true; break; case 'd': doubleStrike = false; break; case 'I': italic = true; break; case 'i': italic = false; break; case 'B': bold = true; break; case 'b': bold = false; break; case 'S': superscript = true; break; case 's': superscript = false; break; case 'U': subscript = true; break; case 'u': subscript = false; break; } break; case '(': // ???: Set a horizontal tab position break; case ')': // ???: Partially delete a horizontal tab position break; case '2': // ???: Clear horizontal tabs break; case 'O': switch (abEscSeq[1]) { case 'S': perforationSkip = parseNumber(2, 2); break; case 'I': // ???: Set page-height(inches) break; default: // ???: Set page-height (lines) break; } break; case '/': //Right margin break; case 'L': leftBorder = parseNumber(1, 3); break; case 'A': // ???: Line-feed 1/6" lineFeed = 12.0; break; case 'B': // ???: Line-feed 1/9" lineFeed = 8.0; break; case 'T': // ???: Line-feed nn/144" lineFeed = parseNumber(1, 2) / 2.0; break; case 'Z': // ???: Line-feed nn/216" lineFeed = parseNumber(1, 2) / 3.0; break; case '[': // ???: Uni-directional printing break; case ']': // ???: Bi-directional printing break; case 'p': detectPaperOut = true; break; case 'q': detectPaperOut = false; break; case 13: // (ESC, CR) Move printer-head to end-position break; case '@': resetEmulatedPrinter(); break; case '\\': rightBorder = parseNumber(1, 3); break; case 'G': graphDensity = parseNumber(1, 3) / 100.0; if (graphDensity < 0.1) { graphDensity = 0.1; } sizeRemainingDataBytes = parseNumber(4, 4); break; case 'S': // Print graphics, density depending on font sizeRemainingDataBytes = parseNumber(1, 4); break; case 'X': underline = true; break; case 'Y': underline = false; break; case '&': case '$': japanese = !japanese; break; case 'f': // ???: Scroll paper forward break; case 'r': // ???: Scroll paper back break; } } void ImagePrinterMSX::processCharacter(byte data) { if (alternateChar) { // Print SOH-preceded character printVisibleCharacter(data & 0x1F); alternateChar = false; } else { switch (data) { case 1: // SOH: A symbolcode preceding code alternateChar = true; break; case 7: // BEL: Audible beep (buzzer, 0.3s) break; case 8: // BS: Backstep (1 Character) // TODO: fix for other font-sizes hpos -= 8; if (hpos < leftBorder) { hpos = leftBorder; } break; case 9: { // HAT: Horizontal tabulator // TODO: fix for other font-sizes hpos = (((unsigned)hpos + 64 - leftBorder) & ~63) + leftBorder; if (hpos < rightBorder) { break; } hpos = leftBorder; // fall thru: CR/LF } case 10: // LF: Carriage return + Line feed case 11: // VT: Vertical tabulator (like LF) //hpos = leftBorder; vpos += lineFeed; if (vpos >= pageHeight) { flushEmulatedPrinter(); } break; case 12: // FF: Form feed ensurePrintPage(); flushEmulatedPrinter(); break; case 13: // CR: Carriage return hpos = leftBorder; break; case 14: // SO: Double character-width on doubleWidth = true; break; case 15: // SI: Double character-width off doubleWidth = false; break; case 27: escSequence = true; break; default: if (data >= 32) { // Yes, we can print it! printVisibleCharacter(data); } break; } } } // class ImagePrinterEpson static const byte EpsonFontRom[] = { 0x8b, 0x04, 0x0a, 0x20, 0x8a, 0x60, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 0 0x8b, 0x1c, 0x22, 0x08, 0xa2, 0x48, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 1 0x9b, 0x00, 0x3c, 0x00, 0x82, 0x40, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 2 0x9a, 0x00, 0x1c, 0x22, 0x80, 0x62, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 3 0x96, 0x00, 0x12, 0x80, 0x5e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 4 0xa7, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 5 0x8b, 0x12, 0x00, 0x7e, 0x80, 0x12, 0x80, 0x02, 0x80, 0x42, 0x00, 0x00, // 6 0xc8, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7 0x8b, 0x06, 0x00, 0x09, 0x00, 0x51, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, // 8 0x8b, 0x5e, 0x80, 0x10, 0x80, 0x08, 0x40, 0x04, 0x40, 0x9e, 0x00, 0x00, // 9 0x8a, 0x40, 0x9e, 0x00, 0x90, 0x40, 0x10, 0x4e, 0x80, 0x00, 0x00, 0x00, // 10 0x8b, 0x92, 0x28, 0x44, 0x00, 0x44, 0x00, 0x44, 0x28, 0x92, 0x00, 0x00, // 11 0x8b, 0xfe, 0x00, 0xa0, 0x00, 0x48, 0x00, 0x1e, 0x00, 0x0a, 0x00, 0x00, // 12 0x8b, 0x06, 0x08, 0x54, 0xa0, 0x04, 0xa0, 0x54, 0x08, 0x06, 0x00, 0x00, // 13 0x8b, 0x04, 0x0a, 0x20, 0x0a, 0xa0, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 14 0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x46, 0x00, 0x44, 0x00, 0x00, 0x00, // 15 0x9a, 0x00, 0x50, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x14, 0x00, 0x00, 0x00, // 16 0x8a, 0x7e, 0x80, 0x00, 0x80, 0x12, 0x80, 0x12, 0x6c, 0x00, 0x00, 0x00, // 17 0x8b, 0x3e, 0x40, 0x90, 0x00, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x00, // 18 0x8b, 0x2c, 0x02, 0x28, 0x02, 0x1c, 0x20, 0x0a, 0x20, 0x1a, 0x00, 0x00, // 19 0x8b, 0x3a, 0x44, 0x00, 0x8a, 0x10, 0xa2, 0x00, 0x44, 0xb8, 0x00, 0x00, // 20 0x8b, 0x02, 0x08, 0x14, 0x22, 0x08, 0x22, 0x14, 0x08, 0x20, 0x00, 0x00, // 21 0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 22 0x8b, 0x06, 0x88, 0x14, 0x20, 0x44, 0x20, 0x14, 0x88, 0x06, 0x00, 0x00, // 23 0x8b, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, // 24 0x8b, 0x3c, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x82, 0x3c, 0x00, 0x00, // 25 0x8b, 0x04, 0x0a, 0xa0, 0x0a, 0x20, 0x0a, 0xa0, 0x1c, 0x02, 0x00, 0x00, // 26 0x9a, 0x00, 0x1c, 0xa2, 0x00, 0x22, 0x00, 0xa2, 0x1c, 0x00, 0x00, 0x00, // 27 0x8a, 0x3c, 0x80, 0x02, 0x00, 0x02, 0x80, 0x3c, 0x02, 0x00, 0x00, 0x00, // 28 0x8b, 0x3e, 0x00, 0x2a, 0x00, 0x6a, 0x80, 0x2a, 0x00, 0x22, 0x00, 0x00, // 29 0x8b, 0x1c, 0x22, 0x08, 0x22, 0x48, 0xa2, 0x08, 0x22, 0x18, 0x00, 0x00, // 30 0x8b, 0xa8, 0x00, 0x68, 0x00, 0x3e, 0x00, 0x68, 0x00, 0xa8, 0x00, 0x00, // 31 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 0xc8, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 33 0xa9, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, // 34 0x8b, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0xfe, 0x00, 0x28, 0x00, 0x00, // 35 0x8b, 0x24, 0x00, 0x54, 0x00, 0xfe, 0x00, 0x54, 0x00, 0x48, 0x00, 0x00, // 36 0x8b, 0xc0, 0x02, 0xc4, 0x08, 0x10, 0x20, 0x46, 0x80, 0x06, 0x00, 0x00, // 37 0x8b, 0x4c, 0xa0, 0x12, 0xa0, 0x4a, 0x00, 0x04, 0x08, 0x12, 0x00, 0x00, // 38 0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 39 0xc9, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, // 40 0xa7, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 41 0x8b, 0x10, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x10, 0x00, 0x00, // 42 0x8b, 0x10, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 43 0x39, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, // 44 0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 45 0xa8, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 46 0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 47 0x8b, 0x38, 0x44, 0x00, 0x82, 0x00, 0x82, 0x00, 0x44, 0x38, 0x00, 0x00, // 48 0xa9, 0x00, 0x00, 0x42, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, // 49 0x8b, 0x42, 0x80, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x62, 0x00, 0x00, // 50 0x8b, 0x84, 0x00, 0x82, 0x00, 0xa2, 0x00, 0xd2, 0x00, 0x8c, 0x00, 0x00, // 51 0x8b, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x00, // 52 0x8b, 0xe4, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x9c, 0x00, 0x00, // 53 0x8b, 0x0c, 0x12, 0x20, 0x52, 0x80, 0x12, 0x00, 0x12, 0x0c, 0x00, 0x00, // 54 0x8b, 0x80, 0x00, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x80, 0x00, 0x00, // 55 0x8b, 0x6c, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x6c, 0x00, 0x00, // 56 0x8b, 0x60, 0x90, 0x00, 0x90, 0x02, 0x94, 0x08, 0x90, 0x60, 0x00, 0x00, // 57 0xa7, 0x00, 0x00, 0x36, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 58 0x27, 0x00, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 59 0x89, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 60 0x8b, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x00, // 61 0xab, 0x00, 0x00, 0x82, 0x00, 0x44, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, // 62 0x8b, 0x40, 0x80, 0x00, 0x80, 0x0a, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, // 63 0x8b, 0x38, 0x44, 0x82, 0x10, 0xaa, 0x00, 0xaa, 0x00, 0x7a, 0x00, 0x00, // 64 0x8b, 0x1e, 0x20, 0x48, 0x80, 0x08, 0x80, 0x48, 0x20, 0x1e, 0x00, 0x00, // 65 0x8b, 0x82, 0x7c, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x6c, 0x00, 0x00, // 66 0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x00, 0x00, // 67 0x8b, 0x82, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, // 68 0x8b, 0xfe, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x82, 0x00, 0x00, // 69 0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x80, 0x00, 0x00, // 70 0x8b, 0x7c, 0x82, 0x00, 0x82, 0x10, 0x82, 0x10, 0x82, 0x5c, 0x00, 0x00, // 71 0x8b, 0xfe, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x00, // 72 0xa9, 0x00, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 73 0x8a, 0x0c, 0x02, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x80, 0x00, 0x00, 0x00, // 74 0x8b, 0xfe, 0x00, 0x10, 0x00, 0x28, 0x00, 0x44, 0x00, 0x82, 0x00, 0x00, // 75 0x8b, 0xfe, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, // 76 0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x20, 0x40, 0x00, 0xfe, 0x00, 0x00, // 77 0x8b, 0xfe, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0xfe, 0x00, 0x00, // 78 0x8b, 0x7c, 0x82, 0x00, 0x82, 0x00, 0x82, 0x00, 0x82, 0x7c, 0x00, 0x00, // 79 0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x60, 0x00, 0x00, // 80 0x8b, 0x7c, 0x82, 0x00, 0x82, 0x08, 0x82, 0x04, 0x80, 0x7a, 0x00, 0x00, // 81 0x8b, 0xfe, 0x00, 0x90, 0x00, 0x90, 0x00, 0x98, 0x04, 0x62, 0x00, 0x00, // 82 0x8b, 0x64, 0x92, 0x00, 0x92, 0x00, 0x92, 0x00, 0x92, 0x4c, 0x00, 0x00, // 83 0x8b, 0x80, 0x00, 0x80, 0x00, 0xfe, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 84 0x8b, 0xfc, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xfc, 0x00, 0x00, // 85 0x8b, 0xe0, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0xe0, 0x00, 0x00, // 86 0x8b, 0xfc, 0x02, 0x04, 0x08, 0x30, 0x08, 0x04, 0x02, 0xfc, 0x00, 0x00, // 87 0x9a, 0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, // 88 0x8b, 0x80, 0x40, 0x20, 0x10, 0x0e, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 89 0x9a, 0x00, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x00, 0x00, 0x00, // 90 0xa9, 0x00, 0x00, 0xfe, 0x00, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, // 91 0x9a, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, // 92 0xa9, 0x00, 0x00, 0x82, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, // 93 0x8b, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, // 94 0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 95 0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 0x8b, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x20, 0x1c, 0x02, 0x00, 0x00, // 97 0x8a, 0xfe, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, 0x00, // 98 0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x00, 0x00, // 99 0x8a, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xfe, 0x00, 0x00, 0x00, // 100 0x8b, 0x1c, 0x22, 0x08, 0x22, 0x08, 0x22, 0x08, 0x22, 0x18, 0x00, 0x00, // 101 0x89, 0x10, 0x00, 0x10, 0x7e, 0x90, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, // 102 0x0a, 0x38, 0x44, 0x01, 0x44, 0x01, 0x44, 0x01, 0x7e, 0x00, 0x00, 0x00, // 103 0x8a, 0xfe, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 104 0x98, 0x00, 0x22, 0x00, 0xbe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 105 0x99, 0x00, 0x01, 0x00, 0x01, 0x20, 0x01, 0xbe, 0x00, 0x00, 0x00, 0x00, // 106 0x9a, 0x00, 0xfe, 0x00, 0x08, 0x00, 0x14, 0x00, 0x22, 0x00, 0x00, 0x00, // 107 0x98, 0x00, 0x82, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 108 0x8b, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, // 109 0x8a, 0x3e, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x1e, 0x00, 0x00, 0x00, // 110 0x8b, 0x1c, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x1c, 0x00, 0x00, // 111 0x0a, 0x7f, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x38, 0x00, 0x00, 0x00, // 112 0x1b, 0x00, 0x38, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x7e, 0x00, 0x00, // 113 0x8a, 0x3e, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, // 114 0x8b, 0x10, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x00, 0x2a, 0x04, 0x00, 0x00, // 115 0x8a, 0x20, 0x00, 0x7c, 0x02, 0x20, 0x02, 0x20, 0x02, 0x00, 0x00, 0x00, // 116 0x8b, 0x3c, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x02, 0x00, 0x00, // 117 0x8b, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 118 0x8b, 0x3c, 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x3c, 0x00, 0x00, // 119 0x89, 0x22, 0x14, 0x00, 0x08, 0x00, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, // 120 0x0b, 0x40, 0x20, 0x11, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 121 0x89, 0x22, 0x04, 0x22, 0x08, 0x22, 0x10, 0x22, 0x00, 0x00, 0x00, 0x00, // 122 0xaa, 0x00, 0x00, 0x10, 0x00, 0x6c, 0x82, 0x00, 0x82, 0x00, 0x00, 0x00, // 123 0xc7, 0x00, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 124 0xaa, 0x00, 0x82, 0x00, 0x82, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // 125 0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 126 0x8b, 0x7c, 0x82, 0x04, 0x8a, 0x10, 0xa2, 0x40, 0x82, 0x7c, 0x00, 0x00, // 127 0x8a, 0x04, 0x0a, 0x80, 0x2a, 0x60, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 128 0x8a, 0x0c, 0x12, 0x28, 0x82, 0x68, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 129 0x8a, 0x0c, 0x32, 0x00, 0x82, 0x40, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 130 0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x42, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 131 0x98, 0x00, 0x02, 0x00, 0x16, 0x88, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, // 132 0xa9, 0x00, 0x00, 0x40, 0xa0, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x00, 0x00, // 133 0x8b, 0x12, 0x00, 0x1e, 0x60, 0x12, 0x80, 0x12, 0x80, 0x40, 0x00, 0x00, // 134 0x9a, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, // 135 0x8a, 0x06, 0x01, 0x08, 0x01, 0x10, 0x21, 0x80, 0x02, 0x00, 0x00, 0x00, // 136 0x8b, 0x06, 0x58, 0x80, 0x08, 0x84, 0x40, 0x06, 0x58, 0x80, 0x00, 0x00, // 137 0x8b, 0x12, 0x4c, 0x80, 0x10, 0x80, 0x50, 0x02, 0x4c, 0x80, 0x00, 0x00, // 138 0x8b, 0x02, 0x18, 0x24, 0x80, 0x44, 0x02, 0x48, 0x30, 0x80, 0x00, 0x00, // 139 0x8b, 0x06, 0x38, 0xc0, 0x20, 0x88, 0x26, 0xd8, 0x02, 0x08, 0x00, 0x00, // 140 0x8b, 0x02, 0x04, 0x08, 0x14, 0x40, 0xa4, 0x00, 0xbe, 0x40, 0x00, 0x00, // 141 0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x8a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 142 0x1b, 0x00, 0x18, 0x21, 0x04, 0x41, 0x06, 0x40, 0x04, 0x40, 0x00, 0x00, // 143 0x8b, 0x02, 0x10, 0x6a, 0x00, 0xaa, 0x00, 0xac, 0x10, 0x80, 0x00, 0x00, // 144 0x8a, 0x06, 0x18, 0x60, 0x00, 0x82, 0x10, 0x82, 0x6c, 0x00, 0x00, 0x00, // 145 0x8b, 0x0e, 0x30, 0x40, 0x90, 0x0e, 0x70, 0x82, 0x10, 0x82, 0x00, 0x00, // 146 0x8b, 0x04, 0x22, 0x08, 0x22, 0x1c, 0x22, 0x08, 0x22, 0x10, 0x00, 0x00, // 147 0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00, // 148 0x8a, 0x0c, 0x11, 0x02, 0x2c, 0x12, 0x20, 0x44, 0x18, 0x00, 0x00, 0x00, // 149 0xa9, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // 150 0x8b, 0x02, 0x04, 0x08, 0x14, 0x80, 0x24, 0x00, 0x3e, 0x80, 0x00, 0x00, // 151 0x8b, 0x0c, 0x12, 0x00, 0xa2, 0x00, 0x22, 0x00, 0xa4, 0x18, 0x00, 0x00, // 152 0x8b, 0x0c, 0x32, 0x00, 0x82, 0x00, 0x02, 0x00, 0x8c, 0x30, 0x00, 0x00, // 153 0x8a, 0x04, 0x0a, 0x20, 0x8a, 0x20, 0x0a, 0x24, 0x9a, 0x00, 0x00, 0x00, // 154 0x8a, 0x0c, 0x12, 0x00, 0xa0, 0x02, 0x00, 0x24, 0x98, 0x00, 0x00, 0x00, // 155 0x8b, 0x0c, 0x32, 0x80, 0x02, 0x00, 0x02, 0x0c, 0xb2, 0x00, 0x00, 0x00, // 156 0x8b, 0x06, 0x18, 0x22, 0x08, 0x22, 0x48, 0x22, 0x80, 0x20, 0x00, 0x00, // 157 0x8a, 0x0c, 0x12, 0x28, 0x02, 0x68, 0x02, 0xa8, 0x10, 0x00, 0x00, 0x00, // 158 0x8b, 0x08, 0x20, 0x88, 0x66, 0x18, 0x20, 0x48, 0x20, 0x80, 0x00, 0x00, // 159 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 160 0x9a, 0x00, 0x02, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 161 0x9a, 0x00, 0x20, 0x40, 0x80, 0x00, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 162 0x8b, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x06, 0x38, 0xc0, 0x28, 0x00, 0x00, // 163 0x8a, 0x00, 0x24, 0x10, 0x46, 0x38, 0xc4, 0x10, 0x48, 0x00, 0x00, 0x00, // 164 0x8b, 0x40, 0x82, 0x44, 0x88, 0x10, 0x22, 0x44, 0x82, 0x04, 0x00, 0x00, // 165 0x8b, 0x0c, 0x10, 0x42, 0xa0, 0x12, 0xa8, 0x44, 0x0a, 0x10, 0x00, 0x00, // 166 0xc8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, // 167 0xba, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 168 0x98, 0x00, 0x02, 0x00, 0x04, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, // 169 0x8b, 0x10, 0x04, 0x50, 0x28, 0x10, 0x28, 0x14, 0x40, 0x10, 0x00, 0x00, // 170 0x8b, 0x10, 0x00, 0x14, 0x08, 0x10, 0x20, 0x50, 0x00, 0x10, 0x00, 0x00, // 171 0x29, 0x00, 0x00, 0x01, 0x04, 0x0a, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // 172 0x8b, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, // 173 0xa8, 0x00, 0x00, 0x02, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // 174 0x9a, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, // 175 0x8b, 0x1c, 0x20, 0x42, 0x00, 0x82, 0x00, 0x84, 0x08, 0x70, 0x00, 0x00, // 176 0x99, 0x00, 0x02, 0x00, 0x46, 0x18, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 177 0x8b, 0x02, 0x40, 0x06, 0x80, 0x0a, 0x80, 0x12, 0x80, 0x60, 0x00, 0x00, // 178 0x8b, 0x04, 0x00, 0x82, 0x00, 0x92, 0x00, 0xb2, 0x4c, 0x80, 0x00, 0x00, // 179 0x8b, 0x08, 0x10, 0x08, 0x20, 0x08, 0x46, 0x38, 0xc0, 0x08, 0x00, 0x00, // 180 0x8b, 0x04, 0x60, 0x82, 0x20, 0x82, 0x20, 0x84, 0x18, 0x80, 0x00, 0x00, // 181 0x8a, 0x0c, 0x10, 0x22, 0x10, 0x42, 0x10, 0x82, 0x0c, 0x00, 0x00, 0x00, // 182 0x8b, 0x80, 0x02, 0x84, 0x08, 0x90, 0x20, 0x80, 0x40, 0x80, 0x00, 0x00, // 183 0x8b, 0x0c, 0x62, 0x10, 0x82, 0x10, 0x82, 0x10, 0x8c, 0x60, 0x00, 0x00, // 184 0x8a, 0x60, 0x02, 0x90, 0x04, 0x90, 0x08, 0x90, 0x60, 0x00, 0x00, 0x00, // 185 0xa9, 0x00, 0x00, 0x02, 0x14, 0x22, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, // 186 0x2a, 0x00, 0x00, 0x01, 0x04, 0x2a, 0x44, 0x28, 0x40, 0x00, 0x00, 0x00, // 187 0x9a, 0x00, 0x10, 0x08, 0x24, 0x02, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, // 188 0x8a, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x08, 0x20, 0x00, 0x00, 0x00, // 189 0x9a, 0x00, 0x02, 0x00, 0x04, 0x80, 0x48, 0x20, 0x10, 0x00, 0x00, 0x00, // 190 0x8a, 0x48, 0x02, 0x80, 0x08, 0x80, 0x10, 0x80, 0x60, 0x00, 0x00, 0x00, // 191 0x8b, 0x1c, 0x20, 0x42, 0x80, 0x12, 0x88, 0x22, 0x88, 0x70, 0x00, 0x00, // 192 0x8b, 0x02, 0x04, 0x08, 0x10, 0x28, 0x40, 0x88, 0x00, 0xfe, 0x00, 0x00, // 193 0x8b, 0x06, 0x98, 0x62, 0x80, 0x12, 0x80, 0x12, 0x8c, 0x60, 0x00, 0x00, // 194 0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x82, 0x00, 0x84, 0x40, 0x00, 0x00, // 195 0x8b, 0x06, 0x98, 0x62, 0x80, 0x02, 0x80, 0x04, 0x88, 0x70, 0x00, 0x00, // 196 0x8b, 0x06, 0x38, 0xc2, 0x10, 0x82, 0x10, 0x82, 0x00, 0x80, 0x00, 0x00, // 197 0x8b, 0x06, 0x38, 0xc0, 0x10, 0x80, 0x10, 0x80, 0x00, 0x80, 0x00, 0x00, // 198 0x8b, 0x1c, 0x22, 0x40, 0x82, 0x00, 0x92, 0x04, 0x98, 0x40, 0x00, 0x00, // 199 0x8b, 0x06, 0x38, 0xc0, 0x10, 0x00, 0x10, 0x06, 0x38, 0xc0, 0x00, 0x00, // 200 0x92, 0x00, 0x02, 0x00, 0x86, 0x18, 0xe2, 0x00, 0x80, 0x00, 0x00, 0x00, // 201 0x8b, 0x0c, 0x02, 0x00, 0x02, 0x80, 0x04, 0x98, 0x60, 0x80, 0x00, 0x00, // 202 0x8b, 0x06, 0x38, 0xc0, 0x10, 0x20, 0x08, 0x44, 0x02, 0x80, 0x00, 0x00, // 203 0x9a, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, // 204 0x8b, 0x06, 0x38, 0xc0, 0x00, 0x30, 0x00, 0x46, 0x38, 0xc0, 0x00, 0x00, // 205 0x8b, 0x06, 0x38, 0xc0, 0x20, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 206 0x8b, 0x0c, 0x32, 0x40, 0x82, 0x00, 0x82, 0x04, 0x98, 0x60, 0x00, 0x00, // 207 0x8b, 0x06, 0x18, 0x60, 0x90, 0x00, 0x90, 0x00, 0x90, 0x60, 0x00, 0x00, // 208 0x8b, 0x1c, 0x20, 0x42, 0x00, 0x8a, 0x00, 0x84, 0x0a, 0x70, 0x00, 0x00, // 209 0x8b, 0x06, 0x18, 0x60, 0x80, 0x10, 0x88, 0x14, 0x82, 0x60, 0x00, 0x00, // 210 0x8b, 0x04, 0x62, 0x00, 0x92, 0x00, 0x92, 0x00, 0x8c, 0x40, 0x00, 0x00, // 211 0x8b, 0x80, 0x00, 0x86, 0x18, 0xe0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, // 212 0x8b, 0x0c, 0x32, 0xc0, 0x02, 0x00, 0x02, 0x0c, 0x30, 0xc0, 0x00, 0x00, // 213 0x9b, 0x00, 0xfe, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, // 214 0x8b, 0x06, 0x38, 0xc4, 0x08, 0x10, 0x08, 0x06, 0x38, 0xc0, 0x00, 0x00, // 215 0x8b, 0x02, 0x84, 0x48, 0x20, 0x18, 0x24, 0x02, 0x40, 0x80, 0x00, 0x00, // 216 0x8b, 0x80, 0x40, 0x26, 0x18, 0x00, 0x20, 0x00, 0x40, 0x80, 0x00, 0x00, // 217 0x8b, 0x02, 0x04, 0x8a, 0x00, 0x92, 0x00, 0xa2, 0x40, 0x80, 0x00, 0x00, // 218 0x9b, 0x00, 0x06, 0x18, 0x62, 0x80, 0x02, 0x80, 0x00, 0x80, 0x00, 0x00, // 219 0xa8, 0x00, 0x00, 0xc0, 0x30, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // 220 0x8a, 0x02, 0x00, 0x02, 0x80, 0x06, 0x98, 0x60, 0x80, 0x00, 0x00, 0x00, // 221 0x9a, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00, // 222 0x0b, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 223 0xb7, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 224 0x8a, 0x04, 0x0a, 0x20, 0x0a, 0x20, 0x0a, 0x24, 0x1a, 0x00, 0x00, 0x00, // 225 0x8a, 0x06, 0x18, 0xe2, 0x00, 0x22, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 226 0x8a, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x00, 0x00, 0x00, // 227 0x8b, 0x0c, 0x10, 0x02, 0x20, 0x02, 0x20, 0x06, 0x38, 0xc0, 0x00, 0x00, // 228 0x8a, 0x0c, 0x12, 0x28, 0x02, 0x28, 0x02, 0x28, 0x10, 0x00, 0x00, 0x00, // 229 0x8b, 0x20, 0x00, 0x26, 0x18, 0x60, 0x00, 0xa0, 0x00, 0x80, 0x00, 0x00, // 230 0x1b, 0x00, 0x18, 0x25, 0x00, 0x45, 0x00, 0x46, 0x18, 0x60, 0x00, 0x00, // 231 0x8a, 0x06, 0x18, 0xe0, 0x00, 0x20, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 232 0x99, 0x00, 0x02, 0x00, 0x26, 0x18, 0x22, 0x80, 0x00, 0x00, 0x00, 0x00, // 233 0x89, 0x01, 0x00, 0x01, 0x00, 0x26, 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, // 234 0x8a, 0x06, 0x18, 0x60, 0x88, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, 0x00, // 235 0x99, 0x00, 0x02, 0x00, 0x06, 0x98, 0x62, 0x80, 0x00, 0x00, 0x00, 0x00, // 236 0x8a, 0x26, 0x18, 0x20, 0x06, 0x38, 0x00, 0x26, 0x18, 0x00, 0x00, 0x00, // 237 0x89, 0x26, 0x18, 0x20, 0x00, 0x20, 0x06, 0x18, 0x00, 0x00, 0x00, 0x00, // 238 0x8a, 0x0c, 0x12, 0x00, 0x20, 0x02, 0x00, 0x24, 0x18, 0x00, 0x00, 0x00, // 239 0x0a, 0x03, 0x1c, 0x60, 0x04, 0x40, 0x04, 0x48, 0x30, 0x00, 0x00, 0x00, // 240 0x1b, 0x00, 0x18, 0x24, 0x00, 0x44, 0x00, 0x47, 0x18, 0x60, 0x00, 0x00, // 241 0x89, 0x06, 0x38, 0x00, 0x10, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, // 242 0x8a, 0x02, 0x10, 0x02, 0x28, 0x02, 0x28, 0x04, 0x20, 0x00, 0x00, 0x00, // 243 0x9a, 0x00, 0x20, 0x0c, 0x32, 0xc0, 0x22, 0x00, 0x20, 0x00, 0x00, 0x00, // 244 0x8a, 0x0c, 0x32, 0x00, 0x02, 0x00, 0x02, 0x0c, 0x32, 0x00, 0x00, 0x00, // 245 0x9a, 0x00, 0x3e, 0x00, 0x04, 0x00, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, // 246 0x8b, 0x0e, 0x30, 0x04, 0x00, 0x18, 0x04, 0x00, 0x06, 0x38, 0x00, 0x00, // 247 0x8b, 0x02, 0x00, 0x24, 0x10, 0x08, 0x04, 0x12, 0x00, 0x20, 0x00, 0x00, // 248 0x1b, 0x00, 0x40, 0x21, 0x12, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, // 249 0x8b, 0x02, 0x00, 0x26, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x20, 0x00, 0x00, // 250 0x9a, 0x00, 0x10, 0x04, 0x1a, 0x60, 0x82, 0x00, 0x80, 0x00, 0x00, 0x00, // 251 0x99, 0x00, 0x02, 0x04, 0x08, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, // 252 0x9a, 0x00, 0x02, 0x00, 0x82, 0x0c, 0xb0, 0x40, 0x10, 0x00, 0x00, 0x00, // 253 0x8b, 0x40, 0x80, 0x00, 0x80, 0x40, 0x20, 0x00, 0x20, 0x40, 0x00, 0x00, // 254 0x8b, 0x1a, 0x24, 0x42, 0x08, 0x92, 0x20, 0x84, 0x48, 0xb0, 0x00, 0x00 // 255 }; ImagePrinterEpson::ImagePrinterEpson(MSXMotherBoard& motherBoard) : ImagePrinter(motherBoard) { graphicsHiLo = false; resetEmulatedPrinter(); } const string& ImagePrinterEpson::getName() const { static const string name("epson-printer"); return name; } const string& ImagePrinterEpson::getDescription() const { // TODO which printer type static const string desc( "Emulate Epson FX80 printer, prints to image."); return desc; } void ImagePrinterEpson::getNumberOfDots(unsigned& dotsX, unsigned& dotsY) { dotsX = 610; dotsY = 825; } void ImagePrinterEpson::resetSettings() { lineFeed = 12.0; leftBorder = 48; rightBorder = leftBorder + 480; graphDensity = 1.0; fontDensity = 1.0; pageTop = 48; lines = 72; fontWidth = 6; eightBit = -1; memcpy(fontInfo.rom, EpsonFontRom, sizeof(fontInfo.rom)); fontInfo.charWidth = 12; fontInfo.pixelDelta = 0.5; fontInfo.useRam = false; } unsigned ImagePrinterEpson::calcEscSequenceLength(byte character) { switch (character & 127) { case '!': case '-': case '/': case '3': case 'A': case 'J': case 'N': case 'Q': case 'R': case 'S': case 'U': case 'W': case 'b': case 'i': case 'j': case 'l': case 'p': case 's': return 1; case '%': case '?': case 'K': case 'L': case 'Z': case '^': return 2; case '*': case ':': case '&': return 3; case 'B': // Set tabs, variable length (up to 16 tabs) return 0; case 'C': // Set form length, variable length (2 or 3) return 0; case 'D': // Set tabs, variable length (up to 32 tabs) return 0; default: return 0; } } unsigned ImagePrinterEpson::parseNumber(unsigned sizeStart, unsigned sizeChars) { unsigned Value = 0; sizeStart += sizeChars; while (sizeChars--) { Value = Value * 256 + abEscSeq[--sizeStart]; } return Value; } void ImagePrinterEpson::processEscSequence() { byte character = abEscSeq[0] & 127; switch (character) { case '!': { // Master Print Mode Select unsigned masterSelect = parseNumber(1, 1); elite = (masterSelect & 1) != 0; compressed = (masterSelect & 4) != 0; bold = (masterSelect & 8) != 0; doubleStrike = (masterSelect & 16) != 0; doubleWidth = (masterSelect & 32) != 0; if (elite) { fontDensity = 1.20; } else if (compressed) { fontDensity = 1.72; } else { fontDensity = 1.00; } break; } case '#': // Accept Eight Bit as-is break; case '%': // Activates Character Set fontInfo.useRam = parseNumber(1, 1) & 1; break; case '&': // Custom character set, variable length ramLoadOffset = 12 * parseNumber(2, 1); ramLoadEnd = 12 * parseNumber(3, 1) + 12; if (ramLoadEnd <= ramLoadOffset) { ramLoadEnd = ramLoadOffset; } break; case '*': // Turn Graphics Mode ON ninePinGraphics = false; switch (parseNumber(1, 1)) { default: case 0: graphDensity = 1.0; break; case 1: case 2: graphDensity = 2.0; break; case 3: graphDensity = 4.0; break; case 4: graphDensity = 1.33; break; case 5: graphDensity = 1.2; break; case 6: graphDensity = 1.5; break; } sizeRemainingDataBytes = parseNumber(2, 2); break; case '-': // Turn Underline Mode ON/OFF underline = parseNumber(1, 1); break; case '/': // Selects Vertical Tab Channel break; case '0': // Sets Line Spacing to 1/8 inch lineFeed = 9.0; break; case '1': // Sets Line Spacing to 7/72 inch lineFeed = 7.0; break; case '2': // Sets Line Spacing to 1/6 inch lineFeed = 12.0; break; case '3': // Sets Line Spacing to n/216 inch lineFeed = (parseNumber(1, 1) & 127) / 3.0; break; case '4': // Turn Italic Mode ON italic = true; break; case '5': // Turn Italic Mode OFF italic = false; break; case '6': // Turn Printing of International Italic characters ON noHighEscapeCodes = true; break; case '7': // Turn Printing of International Italic characters OFF noHighEscapeCodes = false; break; case '8': // Turn Paper Out Sensor ON detectPaperOut = true; break; case '9': // Turn Paper Out Sensor OFF detectPaperOut = false; break; case ':': // Copies Rom Character set to RAM memcpy(fontInfo.ram, fontInfo.rom, sizeof(fontInfo.ram)); break; case '<': // Turn Uni-directional printing ON (left to right) leftToRight = true; break; case '=': // Sets eight bit to 0 eightBit = 0; break; case '>': // Sets eight bit to 1 eightBit = 1; break; case '?': // Redefines Graphics Codes break; case '@': // Reset eightBit = -1; ninePinGraphics = false; graphDensity = 1.0; fontDensity = 1.0; underline = false; lineFeed = 12.0; italic = false; detectPaperOut = false; leftToRight = false; doubleStrike = false; elite = false; compressed = false; rightBorder = 6 * 78; subscript = false; superscript = false; doubleWidth = false; bold = false; proportional = false; fontInfo.useRam = false; noHighEscapeCodes = false; alternateChar = false; countryCode = CC_USA; break; case 'A': // Sets Line Spacing to n/72 inch lineFeed = parseNumber(1, 1) & 127; break; case 'B': // Set tabs, variable length (up to 16 tabs) break; case 'C': // Set form length, variable length (2 or 3) break; case 'D': // Set tabs, variable length (up to 32 tabs) break; case 'E': // Turn Emphasized Mode ON bold = true; break; case 'F': // Turn Emphasized Mode OFF bold = false; break; case 'G': // Turn Double Strike Mode ON doubleStrike = true; break; case 'H': // Turn Double Strike Mode OFF doubleStrike = false; break; case 'I': // Enables printing of chars 1-31 alternateChar = parseNumber(1, 1) & 1; break; case 'J': // Forces Line Feed with n/216 inch vpos += (parseNumber(1, 1) & 127) / 3.0; if (vpos >= pageHeight) { flushEmulatedPrinter(); } break; case 'K': // Turn Single Density Graphics on (480 dot mode) graphDensity = 1.0; ninePinGraphics = false; sizeRemainingDataBytes = parseNumber(1, 2); break; case 'L': // Turn Double Density Graphics on (960 dot mode) graphDensity = 2.0; ninePinGraphics = false; sizeRemainingDataBytes = parseNumber(1, 2); break; case 'M': // Turn Elite mode ON elite = true; fontDensity = 1.20; break; case 'N': // Turn Skip Over Perforation ON break; case 'O': // Turn Skip Over Perforation OFF break; case 'P': // Turn Elite mode OFF elite = false; fontDensity = compressed ? 1.72 : 1.00; break; case 'Q': { // Set Right Margin int width = parseNumber(1, 2); if (width > 78) width = 78; // FIXME Font dependent !! rightBorder = 6 * width; break; } case 'R': // Select International Character Set countryCode = static_cast(parseNumber(1, 1)); if (countryCode > CC_JAPAN) { countryCode = CC_USA; } break; case 'S': { // Turn Script Mode ON int script = parseNumber(1, 1) & 1; superscript = script == 0; subscript = script == 1; break; } case 'T': // Turn Script Mode OFF subscript = false; superscript = false; break; case 'U': // Turn Uni-directional mode ON/OFF leftToRight = parseNumber(1, 1); break; case 'W': // Turn Expanded Mode ON/OFF normalAfterLine = false; doubleWidth = parseNumber(1, 1); break; case 'Y': // Turn High Speed Double Density Graphics ON break; case 'Z': // Turns Quadruple Density Graphics ON graphDensity = 4.0; ninePinGraphics = false; sizeRemainingDataBytes = parseNumber(1, 2); break; case '^': // Turn Nine Pin Graphics Mode ON graphDensity = parseNumber(1, 1) ? 2.0 : 1.0; ninePinGraphics = true; sizeRemainingDataBytes = 2 * parseNumber(2, 2); break; case 'b': // Set Vertical Tab break; case 'i': // Turn Immediate Mode ON/OFF break; case 'j': // Immediate Reverse Line Feed vpos -= (parseNumber(1, 1) & 127) / 3.0; if (vpos < pageTop) { vpos = pageTop; } break; case 'l': // Set Left Margin break; case 'p': // Turn proportional mode ON/OFF proportional = parseNumber(1, 1); break; case 's': // Set Print Speed break; case 127: // Deletes Last Character in Buffer break; } } // International character code translation for the Epson FX-80 printer // US FR DE GB DK SE IT SP JP static byte intlChar35 [9] = { 35, 35, 35, 6, 35, 35, 35, 12, 35 }; static byte intlChar36 [9] = { 36, 36, 36, 36, 36, 11, 36, 36, 36 }; static byte intlChar64 [9] = { 64, 0, 16, 64, 64, 29, 64, 64, 64 }; static byte intlChar91 [9] = { 91, 5, 23, 91, 18, 23, 5, 7, 91 }; static byte intlChar92 [9] = { 92, 15, 24, 92, 20, 24, 92, 9, 31 }; static byte intlChar93 [9] = { 93, 16, 25, 93, 13, 13, 30, 8, 93 }; static byte intlChar94 [9] = { 94, 94, 94, 94, 94, 25, 94, 94, 94 }; static byte intlChar96 [9] = { 96, 96, 96, 96, 96, 30, 2, 96, 96 }; static byte intlChar123[9] = { 123, 30, 26, 123, 19, 26, 0, 22, 123 }; static byte intlChar124[9] = { 124, 2, 27, 124, 21, 27, 3, 10, 124 }; static byte intlChar125[9] = { 125, 1, 28, 125, 14, 14, 1, 125, 125 }; static byte intlChar126[9] = { 126, 22, 17, 126, 126, 28, 4, 126, 126 }; void ImagePrinterEpson::processCharacter(byte data) { if (data >= 32) { if (italic) { data |= 128; } else { data &= 127; } } if (!noHighEscapeCodes && data >= 128 && data < 160) { data &= 31; } // Convert international characters switch (data & 0x7f) { case 35: data = (data & 0x80) | intlChar35 [countryCode]; break; case 36: data = (data & 0x80) | intlChar36 [countryCode]; break; case 64: data = (data & 0x80) | intlChar64 [countryCode]; break; case 91: data = (data & 0x80) | intlChar91 [countryCode]; break; case 92: data = (data & 0x80) | intlChar92 [countryCode]; break; case 93: data = (data & 0x80) | intlChar93 [countryCode]; break; case 94: data = (data & 0x80) | intlChar94 [countryCode]; break; case 96: data = (data & 0x80) | intlChar96 [countryCode]; break; case 123: data = (data & 0x80) | intlChar123[countryCode]; break; case 124: data = (data & 0x80) | intlChar124[countryCode]; break; case 125: data = (data & 0x80) | intlChar125[countryCode]; break; case 126: data = (data & 0x80) | intlChar126[countryCode]; break; } if (data >= 32) { printVisibleCharacter(data); return; } switch (data) { case 0: // Terminates horizontal and vertical TAB setting break; case 7: // Sound beeper break; case 8: // Backspace // TODO: fix for other font-sizes hpos -= 8; if (hpos < leftBorder) { hpos = leftBorder; } break; case 9: { // Horizontal TAB // TODO: fix for other font-sizes hpos = (((unsigned)hpos + 64 - leftBorder) & ~63) + leftBorder; if (hpos < rightBorder) { break; } hpos = leftBorder; // fall thru: CR/LF } case 10: // Line Feed case 11: // Vertical TAB vpos += lineFeed; if (vpos >= pageHeight) { flushEmulatedPrinter(); } break; case 12: // Form Feed ensurePrintPage(); flushEmulatedPrinter(); break; case 13: // Carrige return hpos = leftBorder; break; case 14: // Turns expanded mode ON doubleWidth = true; normalAfterLine = true; break; case 15: // Shift in. Emties buffer, turns compressed mode ON (17.16 cpi) compressed = true; if (!elite) { fontDensity = 1.72; } break; case 17: // Device Control 1: break; case 18: // Device Control 2: turns compressed mode OFF compressed = false; fontDensity = 1.00; break; case 19: // Device Control 3: break; case 20: // Device Control 4: Turns expanded mode OFF doubleWidth = false; break; case 24: // Cancels all text in the print buffer break; case 27: // Escape escSequence = true; break; default: if (alternateChar) { printVisibleCharacter(data); } break; } } // class Paper Paper::Paper(unsigned x, unsigned y) : sizeX(x), sizeY(y) { buf = new byte[x * y]; memset(buf, 255, x * y); } Paper::~Paper() { delete[] buf; } string Paper::save() const { string filename = FileOperations::getNextNumberedFileName( "prints", "page", ".png"); std::vector row_pointers(sizeY); for (unsigned y = 0; y < sizeY; ++y) { row_pointers[y] = &buf[sizeX * y]; } ScreenShotSaver::saveGrayscale(sizeX, sizeY, &row_pointers[0], filename); return filename; } void Paper::setDotSize(double sizeX, double sizeY) { radiusX = sizeX / 2.0; radiusY = sizeY / 2.0; int rx = static_cast(16 * radiusX); int ry = static_cast(16 * radiusY); radius16 = ry; table.clear(); table.resize(2 * (radius16 + 16), -(1 << 30)); int offset = ry + 16; int rx2 = 2 * rx * rx; int ry2 = 2 * ry * ry; int x = 0; int y = ry; int de_x = ry * ry; int de_y = (1 - 2 * ry) * rx * rx; int e = 0; int sx = 0; int sy = rx2 * ry; while (sx <= sy) { table[offset - y - 1] = x; table[offset + y ] = x; x += 1; sx += ry2; e += de_x; de_x += ry2; if ((2 * e + de_y) > 0) { y -= 1; sy -= rx2; e += de_y; de_y += rx2; } } x = rx; y = 0; de_x = (1 - 2 * rx) * ry * ry; de_y = rx * rx; e = 0; sx = ry2 * rx; sy = 0; while (sy <= sx) { table[offset - y - 1] = x; table[offset + y ] = x; y += 1; sy += rx2; e += de_y; de_y += rx2; if ((2 * e + de_x) > 0) { x -= 1; sx -= ry2; e += de_x; de_x += ry2; } } } void Paper::plot(double xPos, double yPos) { unsigned xx1 = max(static_cast(floor(xPos - radiusX)), 0); unsigned xx2 = min(static_cast(ceil (xPos + radiusX)), sizeX); unsigned yy1 = max(static_cast(floor(yPos - radiusY)), 0); unsigned yy2 = min(static_cast(ceil (yPos + radiusY)), sizeY); int y = 16 * yy1 - static_cast(16 * yPos) + 16 + radius16; for (unsigned yy = yy1; yy < yy2; ++yy) { int x = 16 * xx1 - static_cast(16 * xPos); for (unsigned xx = xx1; xx < xx2; ++xx) { int sum = 0; for (int i = 0; i < 16; ++i) { int a = table[y + i]; if (x < -a) { int t = 16 + a + x; if (t > 0) { sum += min(t, 2 * a); } } else { int t = a - x; if (t > 0) { sum += min(16, t); } } } dot(xx, yy) = max(0, dot(xx, yy) - sum); x += 16; } y += 16; } } byte& Paper::dot(unsigned x, unsigned y) { assert(x < sizeX); assert(y < sizeY); return buf[y * sizeX + x]; } } // namespace openmsx