From 0cd761086a72e9fd83c23f1c6267fe79829f3f07 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 28 Jul 2018 14:39:12 +0200 Subject: ADL: Refactor graphics code --- engines/adl/adl.cpp | 17 +- engines/adl/adl_v2.cpp | 11 +- engines/adl/adl_v5.cpp | 2 +- engines/adl/console.cpp | 4 +- engines/adl/display.cpp | 531 ++++--------------------------------------- engines/adl/display.h | 94 ++++---- engines/adl/display_a2.cpp | 477 ++++++++++++++++++++++++++++++++++++++ engines/adl/display_a2.h | 85 +++++++ engines/adl/graphics.cpp | 475 -------------------------------------- engines/adl/graphics.h | 553 +++++++++++++++++++++++++++++++++++++++++++-- engines/adl/hires1.cpp | 24 +- engines/adl/hires2.cpp | 6 +- engines/adl/hires4.cpp | 59 ++--- engines/adl/hires5.cpp | 25 +- engines/adl/hires6.cpp | 30 +-- engines/adl/module.mk | 2 +- 16 files changed, 1275 insertions(+), 1120 deletions(-) create mode 100644 engines/adl/display_a2.cpp create mode 100644 engines/adl/display_a2.h delete mode 100644 engines/adl/graphics.cpp diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 17fdd28892..5da587f391 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -37,7 +37,7 @@ #include "graphics/thumbnail.h" #include "adl/adl.h" -#include "adl/display.h" +#include "adl/display_a2.h" #include "adl/detection.h" #include "adl/graphics.h" #include "adl/sound.h" @@ -259,7 +259,7 @@ byte AdlEngine::inputKey(bool showCursor) const { if (_inputScript && !_scriptPaused) return APPLECHAR('\r'); - _display->updateTextScreen(); + _display->copyTextSurface(); g_system->delayMillis(16); } @@ -703,10 +703,9 @@ void AdlEngine::gameLoop() { } Common::Error AdlEngine::run() { - initGraphics(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2); - + _display = new Display_A2(); _console = new Console(this); - _display = new Display(); + _display->init(); setupOpcodeTables(); @@ -724,7 +723,7 @@ Common::Error AdlEngine::run() { _display->printAsciiString(_strings.lineFeeds); } - _display->setMode(DISPLAY_MODE_MIXED); + _display->setMode(Display::kModeMixed); while (!(_isQuitting || shouldQuit())) gameLoop(); @@ -999,7 +998,7 @@ Common::String AdlEngine::getLine() { if ((byte)line[0] == ('\r' | 0x80)) { _textMode = !_textMode; - _display->setMode(_textMode ? DISPLAY_MODE_TEXT : DISPLAY_MODE_MIXED); + _display->setMode(_textMode ? Display::kModeText : Display::kModeMixed); continue; } @@ -1252,8 +1251,8 @@ int AdlEngine::o_restart(ScriptEnv &e) { if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; - _display->clear(0x00); - _display->updateHiResScreen(); + _graphics->clearScreen(); + _display->copyGfxSurface(); _display->printString(_strings.pressReturn); initState(); _display->printAsciiString(_strings.lineFeeds); diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp index 84829a7f29..aed38beaed 100644 --- a/engines/adl/adl_v2.cpp +++ b/engines/adl/adl_v2.cpp @@ -112,7 +112,7 @@ void AdlEngine_v2::checkTextOverflow(char c) { void AdlEngine_v2::handleTextOverflow() { _linesPrinted = 0; - _display->updateTextScreen(); + _display->copyTextSurface(); if (_inputScript) { // Set pause flag to activate regular behaviour of delay and inputKey @@ -153,7 +153,8 @@ Common::String AdlEngine_v2::loadMessage(uint idx) const { void AdlEngine_v2::printString(const Common::String &str) { Common::String s(str); - uint endPos = TEXT_WIDTH - 1; + const uint textWidth = _display->getTextWidth(); + uint endPos = textWidth - 1; uint startPos = 0; uint pos = 0; @@ -167,7 +168,7 @@ void AdlEngine_v2::printString(const Common::String &str) { } s.setChar(APPLECHAR('\r'), pos); - endPos = pos + TEXT_WIDTH; + endPos = pos + textWidth; startPos = pos + 1; } @@ -181,7 +182,7 @@ void AdlEngine_v2::printString(const Common::String &str) { checkTextOverflow(APPLECHAR('\r')); _display->printChar(APPLECHAR('\r')); - _display->updateTextScreen(); + _display->copyTextSurface(); } void AdlEngine_v2::drawItem(Item &item, const Common::Point &pos) { @@ -259,7 +260,7 @@ void AdlEngine_v2::showRoom() { if (!_state.isDark) drawItems(); - _display->updateHiResScreen(); + _display->copyGfxSurface(); printString(_roomData.description); } diff --git a/engines/adl/adl_v5.cpp b/engines/adl/adl_v5.cpp index b797e73901..9a970d9fdc 100644 --- a/engines/adl/adl_v5.cpp +++ b/engines/adl/adl_v5.cpp @@ -123,7 +123,7 @@ int AdlEngine_v5::o_setTextMode(ScriptEnv &e) { return 1; case 2: _textMode = true; - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); _display->home(); _maxLines = 24; _linesPrinted = 0; diff --git a/engines/adl/console.cpp b/engines/adl/console.cpp index 527a575198..777c0a92b9 100644 --- a/engines/adl/console.cpp +++ b/engines/adl/console.cpp @@ -182,8 +182,8 @@ void Console::prepareGame() { _engine->_graphics->clearScreen(); _engine->loadRoom(_engine->_state.room); _engine->showRoom(); - _engine->_display->updateTextScreen(); - _engine->_display->updateHiResScreen(); + _engine->_display->copyTextSurface(); + _engine->_display->copyGfxSurface(); } bool Console::Cmd_Region(int argc, const char **argv) { diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 52fb1b44d7..f2285a7248 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -20,276 +20,82 @@ * */ -#include "common/stream.h" +#include "common/debug.h" #include "common/rect.h" -#include "common/system.h" #include "common/str.h" -#include "common/config-manager.h" +#include "common/system.h" #include "graphics/surface.h" -#include "graphics/palette.h" -#include "graphics/thumbnail.h" - -#include "engines/util.h" #include "adl/display.h" -#include "adl/adl.h" namespace Adl { -// This implements the Apple II "Hi-Res" display mode - -#define TEXT_BUF_SIZE (TEXT_WIDTH * TEXT_HEIGHT) - -#define COLOR_PALETTE_ENTRIES 8 -static const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { - 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, - 0xc7, 0x34, 0xff, - 0x38, 0xcb, 0x00, - 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, - 0x0d, 0xa1, 0xff, - 0xf2, 0x5e, 0x00 -}; - -// Opacity of the optional scanlines (percentage) -#define SCANLINE_OPACITY 75 - -// Corresponding color in second palette -#define PAL2(X) ((X) | 0x04) - -// Alternate color for odd pixel rows (for scanlines) -#define ALTCOL(X) ((X) | 0x08) - -// Green monochrome palette -#define MONO_PALETTE_ENTRIES 2 -static const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { - 0x00, 0x00, 0x00, - 0x00, 0xc0, 0x01 -}; - -// Uppercase-only Apple II font (manually created). -static const byte font[64][5] = { - { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A - { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC - { 0xfe, 0x82, 0x82, 0x82, 0x7c }, { 0xfe, 0x92, 0x92, 0x92, 0x82 }, // DE - { 0xfe, 0x12, 0x12, 0x12, 0x02 }, { 0x7c, 0x82, 0x82, 0xa2, 0xe2 }, // FG - { 0xfe, 0x10, 0x10, 0x10, 0xfe }, { 0x00, 0x82, 0xfe, 0x82, 0x00 }, // HI - { 0x40, 0x80, 0x80, 0x80, 0x7e }, { 0xfe, 0x10, 0x28, 0x44, 0x82 }, // JK - { 0xfe, 0x80, 0x80, 0x80, 0x80 }, { 0xfe, 0x04, 0x18, 0x04, 0xfe }, // LM - { 0xfe, 0x08, 0x10, 0x20, 0xfe }, { 0x7c, 0x82, 0x82, 0x82, 0x7c }, // NO - { 0xfe, 0x12, 0x12, 0x12, 0x0c }, { 0x7c, 0x82, 0xa2, 0x42, 0xbc }, // PQ - { 0xfe, 0x12, 0x32, 0x52, 0x8c }, { 0x4c, 0x92, 0x92, 0x92, 0x64 }, // RS - { 0x02, 0x02, 0xfe, 0x02, 0x02 }, { 0x7e, 0x80, 0x80, 0x80, 0x7e }, // TU - { 0x3e, 0x40, 0x80, 0x40, 0x3e }, { 0xfe, 0x40, 0x30, 0x40, 0xfe }, // VW - { 0xc6, 0x28, 0x10, 0x28, 0xc6 }, { 0x06, 0x08, 0xf0, 0x08, 0x06 }, // XY - { 0xc2, 0xa2, 0x92, 0x8a, 0x86 }, { 0xfe, 0xfe, 0x82, 0x82, 0x82 }, // Z[ - { 0x04, 0x08, 0x10, 0x20, 0x40 }, { 0x82, 0x82, 0x82, 0xfe, 0xfe }, // \] - { 0x20, 0x10, 0x08, 0x10, 0x20 }, { 0x80, 0x80, 0x80, 0x80, 0x80 }, // ^_ - { 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xbe, 0x00, 0x00 }, // ! - { 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0x28, 0xfe, 0x28, 0xfe, 0x28 }, // "# - { 0x48, 0x54, 0xfe, 0x54, 0x24 }, { 0x46, 0x26, 0x10, 0xc8, 0xc4 }, // $% - { 0x6c, 0x92, 0xac, 0x40, 0xa0 }, { 0x00, 0x00, 0x0e, 0x00, 0x00 }, // &' - { 0x38, 0x44, 0x82, 0x00, 0x00 }, { 0x00, 0x00, 0x82, 0x44, 0x38 }, // () - { 0x44, 0x28, 0xfe, 0x28, 0x44 }, { 0x10, 0x10, 0x7c, 0x10, 0x10 }, // *+ - { 0x00, 0x80, 0x60, 0x00, 0x00 }, { 0x10, 0x10, 0x10, 0x10, 0x10 }, // ,- - { 0x00, 0x00, 0x80, 0x00, 0x00 }, { 0x40, 0x20, 0x10, 0x08, 0x04 }, // ./ - { 0x7c, 0xa2, 0x92, 0x8a, 0x7c }, { 0x00, 0x84, 0xfe, 0x80, 0x00 }, // 01 - { 0xc4, 0xa2, 0x92, 0x92, 0x8c }, { 0x42, 0x82, 0x92, 0x9a, 0x66 }, // 23 - { 0x30, 0x28, 0x24, 0xfe, 0x20 }, { 0x4e, 0x8a, 0x8a, 0x8a, 0x72 }, // 45 - { 0x78, 0x94, 0x92, 0x92, 0x62 }, { 0x02, 0xe2, 0x12, 0x0a, 0x06 }, // 67 - { 0x6c, 0x92, 0x92, 0x92, 0x6c }, { 0x8c, 0x92, 0x92, 0x52, 0x3c }, // 89 - { 0x00, 0x00, 0x28, 0x00, 0x00 }, { 0x00, 0x80, 0x68, 0x00, 0x00 }, // :; - { 0x10, 0x28, 0x44, 0x82, 0x00 }, { 0x28, 0x28, 0x28, 0x28, 0x28 }, // <= - { 0x00, 0x82, 0x44, 0x28, 0x10 }, { 0x04, 0x02, 0xb2, 0x0a, 0x04 } // >? -}; - -Display::Display() : - _mode(DISPLAY_MODE_TEXT), - _cursorPos(0), - _showCursor(false) { - - _monochrome = !ConfMan.getBool("color"); - _scanlines = ConfMan.getBool("scanlines"); - - if (_monochrome) - g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_ENTRIES); - else - g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_ENTRIES); - - showScanlines(_scanlines); - - _frameBuf = new byte[DISPLAY_SIZE]; - memset(_frameBuf, 0, DISPLAY_SIZE); - _frameBufSurface = new Graphics::Surface; - // We need 2x scaling to properly render the half-pixel shift - // of the second palette - _frameBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); - - _textBuf = new byte[TEXT_BUF_SIZE]; - memset(_textBuf, (byte)APPLECHAR(' '), TEXT_BUF_SIZE); - _textBufSurface = new Graphics::Surface; - // For ease of copying, also use 2x scaling here - _textBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); - - createFont(); +Display::~Display() { + delete[] _textBuf; + _textSurface->free(); + delete _textSurface; - _startMillis = g_system->getMillis(); + _gfxSurface->free(); + delete _gfxSurface; } -Display::~Display() { - delete[] _frameBuf; - _frameBufSurface->free(); - delete _frameBufSurface; +void Display::createSurfaces(uint gfxWidth, uint gfxHeight, uint splitHeight) { + _gfxSurface = new Graphics::Surface; + _gfxSurface->create(gfxWidth, gfxHeight, Graphics::PixelFormat::createFormatCLUT8()); + _textSurface = new Graphics::Surface; + _textSurface->create(gfxWidth, gfxHeight, Graphics::PixelFormat::createFormatCLUT8()); + _splitHeight = splitHeight; +} - delete[] _textBuf; - _textBufSurface->free(); - delete _textBufSurface; +void Display::createTextBuffer(uint textWidth, uint textHeight) { + _textWidth = textWidth; + _textHeight = textHeight; - _font->free(); - delete _font; + _textBuf = new byte[textWidth * textHeight]; + memset(_textBuf, asciiToNative(' '), textWidth * textHeight); } -void Display::setMode(DisplayMode mode) { +void Display::setMode(Display::Mode mode) { _mode = mode; - if (_mode == DISPLAY_MODE_TEXT || _mode == DISPLAY_MODE_MIXED) - updateTextScreen(); - if (_mode == DISPLAY_MODE_HIRES || _mode == DISPLAY_MODE_MIXED) - updateHiResScreen(); + if (_mode == Display::kModeText || _mode == Display::kModeMixed) + copyTextSurface(); + if (_mode == Display::kModeGraphics || _mode == Display::kModeMixed) + copyGfxSurface(); } -void Display::updateTextScreen() { +void Display::copyTextSurface() { updateTextSurface(); - if (_mode == DISPLAY_MODE_TEXT) - g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h); - else if (_mode == DISPLAY_MODE_MIXED) - g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2); + if (_mode == Display::kModeText) + g_system->copyRectToScreen(_textSurface->getPixels(), _textSurface->pitch, 0, 0, _textSurface->w, _textSurface->h); + else if (_mode == Display::kModeMixed) + g_system->copyRectToScreen(_textSurface->getBasePtr(0, _textSurface->h - _splitHeight), _textSurface->pitch, 0, _textSurface->h - _splitHeight, _textSurface->w, _splitHeight); g_system->updateScreen(); } -void Display::updateHiResScreen() { - updateHiResSurface(); +void Display::copyGfxSurface() { + updateGfxSurface(); - if (_mode == DISPLAY_MODE_HIRES) - g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h); - else if (_mode == DISPLAY_MODE_MIXED) - g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2); + if (_mode == kModeGraphics) + g_system->copyRectToScreen(_gfxSurface->getPixels(), _gfxSurface->pitch, 0, 0, _gfxSurface->w, _gfxSurface->h); + else if (_mode == kModeMixed) + g_system->copyRectToScreen(_gfxSurface->getPixels(), _gfxSurface->pitch, 0, 0, _gfxSurface->w, _gfxSurface->h - _splitHeight); g_system->updateScreen(); } -bool Display::saveThumbnail(Common::WriteStream &out) { - if (_scanlines) { - showScanlines(false); - g_system->updateScreen(); - } - - bool retval = Graphics::saveThumbnail(out); - - if (_scanlines) { - showScanlines(true); - g_system->updateScreen(); - } - - return retval; -} - -void Display::loadFrameBuffer(Common::ReadStream &stream, byte *dst) { - for (uint j = 0; j < 8; ++j) { - for (uint i = 0; i < 8; ++i) { - stream.read(dst, DISPLAY_PITCH); - dst += DISPLAY_PITCH * 64; - stream.read(dst, DISPLAY_PITCH); - dst += DISPLAY_PITCH * 64; - stream.read(dst, DISPLAY_PITCH); - stream.readUint32LE(); - stream.readUint32LE(); - dst -= DISPLAY_PITCH * 120; - } - dst -= DISPLAY_PITCH * 63; - } - - if (stream.eos() || stream.err()) - error("Failed to read frame buffer"); -} - -void Display::loadFrameBuffer(Common::ReadStream &stream) { - loadFrameBuffer(stream, _frameBuf); -} - -void Display::putPixel(const Common::Point &p, byte color) { - byte offset = p.x / 7; - byte mask = 0x80 | (1 << (p.x % 7)); - - // Since white and black are in both palettes, we leave - // the palette bit alone - if ((color & 0x7f) == 0x7f || (color & 0x7f) == 0) - mask &= 0x7f; - - // Adjust colors starting with bits '01' or '10' for - // odd offsets - if (offset & 1) { - byte c = color << 1; - if (c >= 0x40 && c < 0xc0) - color ^= 0x7f; - } - - writeFrameBuffer(p, color, mask); -} - -void Display::setPixelByte(const Common::Point &p, byte color) { - assert(p.x >= 0 && p.x < DISPLAY_WIDTH && p.y >= 0 && p.y < DISPLAY_HEIGHT); - - _frameBuf[p.y * DISPLAY_PITCH + p.x / 7] = color; -} - -void Display::setPixelBit(const Common::Point &p, byte color) { - writeFrameBuffer(p, color, 1 << (p.x % 7)); -} - -void Display::setPixelPalette(const Common::Point &p, byte color) { - writeFrameBuffer(p, color, 0x80); -} - -byte Display::getPixelByte(const Common::Point &p) const { - assert(p.x >= 0 && p.x < DISPLAY_WIDTH && p.y >= 0 && p.y < DISPLAY_HEIGHT); - - return _frameBuf[p.y * DISPLAY_PITCH + p.x / 7]; -} - -bool Display::getPixelBit(const Common::Point &p) const { - assert(p.x >= 0 && p.x < DISPLAY_WIDTH && p.y >= 0 && p.y < DISPLAY_HEIGHT); - - byte *b = _frameBuf + p.y * DISPLAY_PITCH + p.x / 7; - return *b & (1 << (p.x % 7)); -} - -void Display::clear(byte color) { - byte val = 0; - - byte c = color << 1; - if (c >= 0x40 && c < 0xc0) - val = 0x7f; - - for (uint i = 0; i < DISPLAY_SIZE; ++i) { - _frameBuf[i] = color; - color ^= val; - } -} - void Display::home() { - memset(_textBuf, (byte)APPLECHAR(' '), TEXT_BUF_SIZE); + memset(_textBuf, asciiToNative(' '), _textWidth * _textHeight); _cursorPos = 0; } void Display::moveCursorForward() { ++_cursorPos; - if (_cursorPos >= TEXT_BUF_SIZE) + if (_cursorPos >= _textWidth * _textHeight) scrollUp(); } @@ -299,276 +105,37 @@ void Display::moveCursorBackward() { } void Display::moveCursorTo(const Common::Point &pos) { - _cursorPos = pos.y * TEXT_WIDTH + pos.x; + _cursorPos = pos.y * _textWidth + pos.x; - if (_cursorPos >= TEXT_BUF_SIZE) + if (_cursorPos >= _textWidth * _textHeight) error("Cursor position (%i, %i) out of bounds", pos.x, pos.y); } -// FIXME: This does not currently update the surfaces -void Display::printChar(char c) { - if (c == APPLECHAR('\r')) - _cursorPos = (_cursorPos / TEXT_WIDTH + 1) * TEXT_WIDTH; - else if (c == APPLECHAR('\a')) { - updateTextScreen(); - static_cast(g_engine)->bell(); - } else if ((byte)c < 0x80 || (byte)c >= 0xa0) { - setCharAtCursor(c); - ++_cursorPos; - } - - if (_cursorPos == TEXT_BUF_SIZE) - scrollUp(); -} - void Display::printString(const Common::String &str) { Common::String::const_iterator c; for (c = str.begin(); c != str.end(); ++c) printChar(*c); - updateTextScreen(); + copyTextSurface(); } void Display::printAsciiString(const Common::String &str) { - Common::String aStr; - - Common::String::const_iterator it; - for (it = str.begin(); it != str.end(); ++it) - aStr += APPLECHAR(*it); + Common::String::const_iterator c; + for (c = str.begin(); c != str.end(); ++c) + printChar(asciiToNative(*c)); - printString(aStr); + copyTextSurface(); } void Display::setCharAtCursor(byte c) { _textBuf[_cursorPos] = c; } -void Display::showCursor(bool enable) { - _showCursor = enable; -} - -void Display::writeFrameBuffer(const Common::Point &p, byte color, byte mask) { - assert(p.x >= 0 && p.x < DISPLAY_WIDTH && p.y >= 0 && p.y < DISPLAY_HEIGHT); - - byte *b = _frameBuf + p.y * DISPLAY_PITCH + p.x / 7; - color ^= *b; - color &= mask; - *b ^= color; -} - -void Display::showScanlines(bool enable) { - byte pal[COLOR_PALETTE_ENTRIES * 3]; - - g_system->getPaletteManager()->grabPalette(pal, 0, COLOR_PALETTE_ENTRIES); - - if (enable) { - for (uint i = 0; i < ARRAYSIZE(pal); ++i) - pal[i] = pal[i] * (100 - SCANLINE_OPACITY) / 100; - } - - g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES); -} - -static byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { - byte color = 0; - - switch (bits & 0x7) { - case 0x3: // 011 (white) - case 0x6: // 110 - case 0x7: // 111 - color = 1; - break; - case 0x2: // 010 (color) - color = 2 + odd; - break; - case 0x5: // 101 (color) - color = 2 + !odd; - } - - if (secondPal) - color = PAL2(color); - - odd = !odd; - bits >>= 1; - - return color; -} - -static void renderPixelRowColor(byte *dst, byte *src) { - uint16 bits = (src[0] & 0x7f) << 1; - byte pal = src[0] >> 7; - - if (pal != 0) - *dst++ = 0; - - bool odd = false; - - for (uint i = 0; i < DISPLAY_PITCH; ++i) { - if (i != DISPLAY_PITCH - 1) { - bits |= (src[i + 1] & 0x7f) << 8; - pal |= (src[i + 1] >> 7) << 1; - } - - // For the first 6 bits in the block we draw two pixels - for (uint j = 0; j < 6; ++j) { - byte color = processColorBits(bits, odd, pal & 1); - *dst++ = color; - *dst++ = color; - } - - // Last bit of the block, draw one, two or three pixels - byte color = processColorBits(bits, odd, pal & 1); - - // Draw the first pixel - *dst++ = color; - - switch (pal) { - case 0x0: - case 0x3: - // If palette stays the same, draw a second pixel - *dst++ = color; - break; - case 0x2: - // If we're moving from first to second palette, - // draw a second pixel, and a third in the second - // palette. - *dst++ = color; - *dst++ = PAL2(color); - } - - pal >>= 1; - } -} - -static void renderPixelRowMono(byte *dst, byte *src) { - byte pal = src[0] >> 7; - - if (pal != 0) - *dst++ = 0; - - for (uint i = 0; i < DISPLAY_PITCH; ++i) { - if (i != DISPLAY_PITCH - 1) - pal |= (src[i + 1] >> 7) << 1; - - for (uint j = 0; j < 6; ++j) { - bool color = src[i] & (1 << j); - *dst++ = color; - *dst++ = color; - } - - bool color = src[i] & (1 << 6); - - *dst++ = color; - - switch (pal) { - case 0x0: - case 0x3: - *dst++ = color; - break; - case 0x2: - *dst++ = color; - *dst++ = color; - } - - pal >>= 1; - } -} - -static void copyEvenSurfaceRows(Graphics::Surface &surf) { - byte *src = (byte *)surf.getPixels(); - - for (uint y = 0; y < surf.h / 2; ++y) { - byte *dst = src + surf.pitch; - for (uint x = 0; x < surf.w; ++x) - dst[x] = ALTCOL(src[x]); - src += surf.pitch * 2; - } -} - -void Display::updateHiResSurface() { - byte *src = _frameBuf; - byte *dst = (byte *)_frameBufSurface->getPixels(); - - for (uint i = 0; i < DISPLAY_HEIGHT; ++i) { - if (_monochrome) - renderPixelRowMono(dst, src); - else - renderPixelRowColor(dst, src); - src += DISPLAY_PITCH; - dst += _frameBufSurface->pitch * 2; - } - - copyEvenSurfaceRows(*_frameBufSurface); -} - -void Display::updateTextSurface() { - for (uint row = 0; row < 24; ++row) - for (uint col = 0; col < TEXT_WIDTH; ++col) { - uint charPos = row * TEXT_WIDTH + col; - char c = _textBuf[row * TEXT_WIDTH + col]; - - if (charPos == _cursorPos && _showCursor) - c = (c & 0x3f) | 0x40; - - Common::Rect r(7 * 2, 8 * 2); - r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); - - if (!(c & 0x80)) { - // Blink text. We subtract _startMillis to make this compatible - // with the event recorder, which returns offsetted values on - // playback. - const uint32 millisPassed = g_system->getMillis() - _startMillis; - if (!(c & 0x40) || ((millisPassed / 270) & 1)) - r.translate(0, 4 * 8 * 2); - } - - _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); - } -} - -void Display::drawChar(byte c, int x, int y) { - byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; - - for (uint row = 0; row < 8; ++row) { - for (uint col = 1; col < 6; ++col) { - if (font[c][col - 1] & (1 << row)) { - buf[col * 2] = 1; - buf[col * 2 + 1] = 1; - } - } - - buf += 2 * _font->pitch; - } -} - -void Display::createFont() { - _font = new Graphics::Surface; - _font->create(16 * 7 * 2, 4 * 8 * 2 * 2, Graphics::PixelFormat::createFormatCLUT8()); - - for (uint i = 0; i < 4; ++i) - for (uint j = 0; j < 16; ++j) - drawChar(i * 16 + j, j * 7 * 2, i * 8 * 2); - - // Create inverted font - byte *buf = (byte *)_font->getPixels(); - byte *bufInv = buf + (_font->h / 2) * _font->pitch; - - for (uint row = 0; row < _font->h / 2; row += 2) { - for (uint col = 0; col < _font->w; ++col) - bufInv[col] = (buf[col] ? 0 : 1); - - buf += _font->pitch * 2; - bufInv += _font->pitch * 2; - } - - copyEvenSurfaceRows(*_font); -} - void Display::scrollUp() { - memmove(_textBuf, _textBuf + TEXT_WIDTH, TEXT_BUF_SIZE - TEXT_WIDTH); - memset(_textBuf + TEXT_BUF_SIZE - TEXT_WIDTH, (byte)APPLECHAR(' '), TEXT_WIDTH); - if (_cursorPos >= TEXT_WIDTH) - _cursorPos -= TEXT_WIDTH; + memmove(_textBuf, _textBuf + _textWidth, (_textHeight - 1) * _textWidth); + memset(_textBuf + (_textHeight - 1) * _textWidth, asciiToNative(' '), _textWidth); + if (_cursorPos >= _textWidth) + _cursorPos -= _textWidth; } } // End of namespace Adl diff --git a/engines/adl/display.h b/engines/adl/display.h index c1c0f410fe..d4a30cfe78 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -23,10 +23,12 @@ #ifndef ADL_DISPLAY_H #define ADL_DISPLAY_H +// REMOVE +#define APPLECHAR(C) (char)(C | 0x80) + #include "common/types.h" namespace Common { -class ReadStream; class WriteStream; class String; struct Point; @@ -38,76 +40,56 @@ struct Surface; namespace Adl { -#define DISPLAY_WIDTH 280 -#define DISPLAY_HEIGHT 192 -#define DISPLAY_PITCH (DISPLAY_WIDTH / 7) -#define DISPLAY_SIZE (DISPLAY_PITCH * DISPLAY_HEIGHT) -#define TEXT_WIDTH 40 -#define TEXT_HEIGHT 24 - -enum DisplayMode { - DISPLAY_MODE_HIRES, - DISPLAY_MODE_TEXT, - DISPLAY_MODE_MIXED -}; - -#define APPLECHAR(C) ((char)((C) | 0x80)) - class Display { public: - Display(); - ~Display(); - - void setMode(DisplayMode mode); - void updateTextScreen(); - void updateHiResScreen(); - bool saveThumbnail(Common::WriteStream &out); - - // Graphics - static void loadFrameBuffer(Common::ReadStream &stream, byte *dst); - void loadFrameBuffer(Common::ReadStream &stream); - void putPixel(const Common::Point &p, byte color); - void setPixelByte(const Common::Point &p, byte color); - void setPixelBit(const Common::Point &p, byte color); - void setPixelPalette(const Common::Point &p, byte color); - byte getPixelByte(const Common::Point &p) const; - bool getPixelBit(const Common::Point &p) const; - void clear(byte color); - - // Text + enum Mode { + kModeGraphics, + kModeText, + kModeMixed + }; + + virtual ~Display(); + + virtual void init() = 0; + virtual bool saveThumbnail(Common::WriteStream &out) = 0; + void setMode(Mode mode); + void copyTextSurface(); + void copyGfxSurface(); + + virtual char asciiToNative(char c) const = 0; + virtual void printChar(char c) = 0; + virtual void showCursor(bool enable) = 0; void home(); void moveCursorTo(const Common::Point &pos); void moveCursorForward(); void moveCursorBackward(); - void printChar(char c); void printString(const Common::String &str); void printAsciiString(const Common::String &str); void setCharAtCursor(byte c); - void showCursor(bool enable); - -private: - void writeFrameBuffer(const Common::Point &p, byte color, byte mask); - void updateHiResSurface(); - void showScanlines(bool enable); - - void updateTextSurface(); - void drawChar(byte c, int x, int y); - void createFont(); + uint getTextWidth() const { return _textWidth; } + uint getTextHeight() const { return _textHeight; } void scrollUp(); - DisplayMode _mode; +protected: + Display() : _textBuf(nullptr), _textSurface(nullptr), _gfxSurface(nullptr), _cursorPos(0), + _mode(kModeText), _splitHeight(0), _textWidth(0), _textHeight(0) { } - byte *_frameBuf; - Graphics::Surface *_frameBufSurface; - bool _scanlines; - bool _monochrome; + void createSurfaces(uint gfxWidth, uint gfxHeight, uint splitHeight); + void createTextBuffer(uint textWidth, uint textHeight); byte *_textBuf; - Graphics::Surface *_textBufSurface; - Graphics::Surface *_font; + Graphics::Surface *_textSurface; + Graphics::Surface *_gfxSurface; uint _cursorPos; - bool _showCursor; - uint32 _startMillis; + +private: + virtual void updateTextSurface() = 0; + virtual void updateGfxSurface() = 0; + + Mode _mode; + uint _splitHeight; + uint _textWidth; + uint _textHeight; }; } // End of namespace Adl diff --git a/engines/adl/display_a2.cpp b/engines/adl/display_a2.cpp new file mode 100644 index 0000000000..393e38bab1 --- /dev/null +++ b/engines/adl/display_a2.cpp @@ -0,0 +1,477 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "common/stream.h" +#include "common/rect.h" +#include "common/system.h" +#include "common/str.h" +#include "common/config-manager.h" + +#include "graphics/surface.h" +#include "graphics/palette.h" +#include "graphics/thumbnail.h" + +#include "engines/util.h" + +#include "adl/display_a2.h" +#include "adl/adl.h" + +namespace Adl { + +#define COLOR_PALETTE_ENTRIES 8 +static const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = { + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, + 0xc7, 0x34, 0xff, + 0x38, 0xcb, 0x00, + 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, + 0x0d, 0xa1, 0xff, + 0xf2, 0x5e, 0x00 +}; + +// Opacity of the optional scanlines (percentage) +#define SCANLINE_OPACITY 75 + +// Corresponding color in second palette +#define PAL2(X) ((X) | 0x04) + +// Alternate color for odd pixel rows (for scanlines) +#define ALTCOL(X) ((X) | 0x08) + +// Green monochrome palette +#define MONO_PALETTE_ENTRIES 2 +static const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = { + 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x01 +}; + +// Uppercase-only Apple II font (manually created). +static const byte font[64][5] = { + { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A + { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC + { 0xfe, 0x82, 0x82, 0x82, 0x7c }, { 0xfe, 0x92, 0x92, 0x92, 0x82 }, // DE + { 0xfe, 0x12, 0x12, 0x12, 0x02 }, { 0x7c, 0x82, 0x82, 0xa2, 0xe2 }, // FG + { 0xfe, 0x10, 0x10, 0x10, 0xfe }, { 0x00, 0x82, 0xfe, 0x82, 0x00 }, // HI + { 0x40, 0x80, 0x80, 0x80, 0x7e }, { 0xfe, 0x10, 0x28, 0x44, 0x82 }, // JK + { 0xfe, 0x80, 0x80, 0x80, 0x80 }, { 0xfe, 0x04, 0x18, 0x04, 0xfe }, // LM + { 0xfe, 0x08, 0x10, 0x20, 0xfe }, { 0x7c, 0x82, 0x82, 0x82, 0x7c }, // NO + { 0xfe, 0x12, 0x12, 0x12, 0x0c }, { 0x7c, 0x82, 0xa2, 0x42, 0xbc }, // PQ + { 0xfe, 0x12, 0x32, 0x52, 0x8c }, { 0x4c, 0x92, 0x92, 0x92, 0x64 }, // RS + { 0x02, 0x02, 0xfe, 0x02, 0x02 }, { 0x7e, 0x80, 0x80, 0x80, 0x7e }, // TU + { 0x3e, 0x40, 0x80, 0x40, 0x3e }, { 0xfe, 0x40, 0x30, 0x40, 0xfe }, // VW + { 0xc6, 0x28, 0x10, 0x28, 0xc6 }, { 0x06, 0x08, 0xf0, 0x08, 0x06 }, // XY + { 0xc2, 0xa2, 0x92, 0x8a, 0x86 }, { 0xfe, 0xfe, 0x82, 0x82, 0x82 }, // Z[ + { 0x04, 0x08, 0x10, 0x20, 0x40 }, { 0x82, 0x82, 0x82, 0xfe, 0xfe }, // \] + { 0x20, 0x10, 0x08, 0x10, 0x20 }, { 0x80, 0x80, 0x80, 0x80, 0x80 }, // ^_ + { 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xbe, 0x00, 0x00 }, // ! + { 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0x28, 0xfe, 0x28, 0xfe, 0x28 }, // "# + { 0x48, 0x54, 0xfe, 0x54, 0x24 }, { 0x46, 0x26, 0x10, 0xc8, 0xc4 }, // $% + { 0x6c, 0x92, 0xac, 0x40, 0xa0 }, { 0x00, 0x00, 0x0e, 0x00, 0x00 }, // &' + { 0x38, 0x44, 0x82, 0x00, 0x00 }, { 0x00, 0x00, 0x82, 0x44, 0x38 }, // () + { 0x44, 0x28, 0xfe, 0x28, 0x44 }, { 0x10, 0x10, 0x7c, 0x10, 0x10 }, // *+ + { 0x00, 0x80, 0x60, 0x00, 0x00 }, { 0x10, 0x10, 0x10, 0x10, 0x10 }, // ,- + { 0x00, 0x00, 0x80, 0x00, 0x00 }, { 0x40, 0x20, 0x10, 0x08, 0x04 }, // ./ + { 0x7c, 0xa2, 0x92, 0x8a, 0x7c }, { 0x00, 0x84, 0xfe, 0x80, 0x00 }, // 01 + { 0xc4, 0xa2, 0x92, 0x92, 0x8c }, { 0x42, 0x82, 0x92, 0x9a, 0x66 }, // 23 + { 0x30, 0x28, 0x24, 0xfe, 0x20 }, { 0x4e, 0x8a, 0x8a, 0x8a, 0x72 }, // 45 + { 0x78, 0x94, 0x92, 0x92, 0x62 }, { 0x02, 0xe2, 0x12, 0x0a, 0x06 }, // 67 + { 0x6c, 0x92, 0x92, 0x92, 0x6c }, { 0x8c, 0x92, 0x92, 0x52, 0x3c }, // 89 + { 0x00, 0x00, 0x28, 0x00, 0x00 }, { 0x00, 0x80, 0x68, 0x00, 0x00 }, // :; + { 0x10, 0x28, 0x44, 0x82, 0x00 }, { 0x28, 0x28, 0x28, 0x28, 0x28 }, // <= + { 0x00, 0x82, 0x44, 0x28, 0x10 }, { 0x04, 0x02, 0xb2, 0x0a, 0x04 } // >? +}; + +Display_A2::Display_A2() : _showCursor(false) { + initGraphics(Display_A2::kGfxWidth * 2, Display_A2::kGfxHeight * 2); +} + +Display_A2::~Display_A2() { + delete[] _frameBuf; + + if (_font) { + _font->free(); + delete _font; + } +} + +void Display_A2::init() { + _monochrome = !ConfMan.getBool("color"); + _scanlines = ConfMan.getBool("scanlines"); + + if (_monochrome) + g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_ENTRIES); + else + g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_ENTRIES); + + showScanlines(_scanlines); + + // We need 2x scaling to properly render the half-pixel shift + // of the second palette + createSurfaces(Display_A2::kGfxWidth * 2, Display_A2::kGfxHeight * 2, 64); + createTextBuffer(Display_A2::kTextWidth, Display_A2::kTextHeight); + + _frameBuf = new byte[Display_A2::kGfxSize]; + memset(_frameBuf, 0, Display_A2::kGfxSize); + + createFont(); + + _startMillis = g_system->getMillis(); +} + +bool Display_A2::saveThumbnail(Common::WriteStream &out) { + if (_scanlines) { + showScanlines(false); + g_system->updateScreen(); + } + + bool retval = Graphics::saveThumbnail(out); + + if (_scanlines) { + showScanlines(true); + g_system->updateScreen(); + } + + return retval; +} + +void Display_A2::loadFrameBuffer(Common::ReadStream &stream, byte *dst) { + for (uint j = 0; j < 8; ++j) { + for (uint i = 0; i < 8; ++i) { + stream.read(dst, Display_A2::kGfxPitch); + dst += Display_A2::kGfxPitch * 64; + stream.read(dst, Display_A2::kGfxPitch); + dst += Display_A2::kGfxPitch * 64; + stream.read(dst, Display_A2::kGfxPitch); + stream.readUint32LE(); + stream.readUint32LE(); + dst -= Display_A2::kGfxPitch * 120; + } + dst -= Display_A2::kGfxPitch * 63; + } + + if (stream.eos() || stream.err()) + error("Failed to read frame buffer"); +} + +void Display_A2::loadFrameBuffer(Common::ReadStream &stream) { + loadFrameBuffer(stream, _frameBuf); +} + +void Display_A2::putPixel(const Common::Point &p, byte color) { + byte offset = p.x / 7; + byte mask = 0x80 | (1 << (p.x % 7)); + + // Since white and black are in both palettes, we leave + // the palette bit alone + if ((color & 0x7f) == 0x7f || (color & 0x7f) == 0) + mask &= 0x7f; + + // Adjust colors starting with bits '01' or '10' for + // odd offsets + if (offset & 1) { + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + color ^= 0x7f; + } + + writeFrameBuffer(p, color, mask); +} + +void Display_A2::setPixelByte(const Common::Point &p, byte color) { + assert(p.x >= 0 && p.x < Display_A2::kGfxWidth && p.y >= 0 && p.y < Display_A2::kGfxHeight); + + _frameBuf[p.y * Display_A2::kGfxPitch + p.x / 7] = color; +} + +void Display_A2::setPixelBit(const Common::Point &p, byte color) { + writeFrameBuffer(p, color, 1 << (p.x % 7)); +} + +void Display_A2::setPixelPalette(const Common::Point &p, byte color) { + writeFrameBuffer(p, color, 0x80); +} + +byte Display_A2::getPixelByte(const Common::Point &p) const { + assert(p.x >= 0 && p.x < Display_A2::kGfxWidth && p.y >= 0 && p.y < Display_A2::kGfxHeight); + + return _frameBuf[p.y * Display_A2::kGfxPitch + p.x / 7]; +} + +bool Display_A2::getPixelBit(const Common::Point &p) const { + assert(p.x >= 0 && p.x < Display_A2::kGfxWidth && p.y >= 0 && p.y < Display_A2::kGfxHeight); + + byte *b = _frameBuf + p.y * Display_A2::kGfxPitch + p.x / 7; + return *b & (1 << (p.x % 7)); +} + +void Display_A2::clear(byte color) { + byte val = 0; + + byte c = color << 1; + if (c >= 0x40 && c < 0xc0) + val = 0x7f; + + for (uint i = 0; i < Display_A2::kGfxSize; ++i) { + _frameBuf[i] = color; + color ^= val; + } +} + +// FIXME: This does not currently update the surfaces +void Display_A2::printChar(char c) { + if (c == APPLECHAR('\r')) + _cursorPos = (_cursorPos / Display_A2::kTextWidth + 1) * Display_A2::kTextWidth; + else if (c == APPLECHAR('\a')) { + copyTextSurface(); + static_cast(g_engine)->bell(); + } else if ((byte)c < 0x80 || (byte)c >= 0xa0) { + setCharAtCursor(c); + ++_cursorPos; + } + + if (_cursorPos == Display_A2::kTextWidth * Display_A2::kTextHeight) + scrollUp(); +} + +void Display_A2::showCursor(bool enable) { + _showCursor = enable; +} + +void Display_A2::writeFrameBuffer(const Common::Point &p, byte color, byte mask) { + assert(p.x >= 0 && p.x < Display_A2::kGfxWidth && p.y >= 0 && p.y < Display_A2::kGfxHeight); + + byte *b = _frameBuf + p.y * Display_A2::kGfxPitch + p.x / 7; + color ^= *b; + color &= mask; + *b ^= color; +} + +void Display_A2::showScanlines(bool enable) { + byte pal[COLOR_PALETTE_ENTRIES * 3]; + + g_system->getPaletteManager()->grabPalette(pal, 0, COLOR_PALETTE_ENTRIES); + + if (enable) { + for (uint i = 0; i < ARRAYSIZE(pal); ++i) + pal[i] = pal[i] * (100 - SCANLINE_OPACITY) / 100; + } + + g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES); +} + +static byte processColorBits(uint16 &bits, bool &odd, bool secondPal) { + byte color = 0; + + switch (bits & 0x7) { + case 0x3: // 011 (white) + case 0x6: // 110 + case 0x7: // 111 + color = 1; + break; + case 0x2: // 010 (color) + color = 2 + odd; + break; + case 0x5: // 101 (color) + color = 2 + !odd; + } + + if (secondPal) + color = PAL2(color); + + odd = !odd; + bits >>= 1; + + return color; +} + +static void renderPixelRowColor(byte *dst, byte *src) { + uint16 bits = (src[0] & 0x7f) << 1; + byte pal = src[0] >> 7; + + if (pal != 0) + *dst++ = 0; + + bool odd = false; + + for (uint i = 0; i < Display_A2::kGfxPitch; ++i) { + if (i != Display_A2::kGfxPitch - 1) { + bits |= (src[i + 1] & 0x7f) << 8; + pal |= (src[i + 1] >> 7) << 1; + } + + // For the first 6 bits in the block we draw two pixels + for (uint j = 0; j < 6; ++j) { + byte color = processColorBits(bits, odd, pal & 1); + *dst++ = color; + *dst++ = color; + } + + // Last bit of the block, draw one, two or three pixels + byte color = processColorBits(bits, odd, pal & 1); + + // Draw the first pixel + *dst++ = color; + + switch (pal) { + case 0x0: + case 0x3: + // If palette stays the same, draw a second pixel + *dst++ = color; + break; + case 0x2: + // If we're moving from first to second palette, + // draw a second pixel, and a third in the second + // palette. + *dst++ = color; + *dst++ = PAL2(color); + } + + pal >>= 1; + } +} + +static void renderPixelRowMono(byte *dst, byte *src) { + byte pal = src[0] >> 7; + + if (pal != 0) + *dst++ = 0; + + for (uint i = 0; i < Display_A2::kGfxPitch; ++i) { + if (i != Display_A2::kGfxPitch - 1) + pal |= (src[i + 1] >> 7) << 1; + + for (uint j = 0; j < 6; ++j) { + bool color = src[i] & (1 << j); + *dst++ = color; + *dst++ = color; + } + + bool color = src[i] & (1 << 6); + + *dst++ = color; + + switch (pal) { + case 0x0: + case 0x3: + *dst++ = color; + break; + case 0x2: + *dst++ = color; + *dst++ = color; + } + + pal >>= 1; + } +} + +static void copyEvenSurfaceRows(Graphics::Surface &surf) { + byte *src = (byte *)surf.getPixels(); + + for (uint y = 0; y < surf.h / 2; ++y) { + byte *dst = src + surf.pitch; + for (uint x = 0; x < surf.w; ++x) + dst[x] = ALTCOL(src[x]); + src += surf.pitch * 2; + } +} + +void Display_A2::updateGfxSurface() { + byte *src = _frameBuf; + byte *dst = (byte *)_gfxSurface->getPixels(); + + for (uint i = 0; i < Display_A2::kGfxHeight; ++i) { + if (_monochrome) + renderPixelRowMono(dst, src); + else + renderPixelRowColor(dst, src); + src += Display_A2::kGfxPitch; + dst += _gfxSurface->pitch * 2; + } + + copyEvenSurfaceRows(*_gfxSurface); +} + +void Display_A2::updateTextSurface() { + for (uint row = 0; row < 24; ++row) + for (uint col = 0; col < Display_A2::kTextWidth; ++col) { + uint charPos = row * Display_A2::kTextWidth + col; + char c = _textBuf[row * Display_A2::kTextWidth + col]; + + if (charPos == _cursorPos && _showCursor) + c = (c & 0x3f) | 0x40; + + Common::Rect r(7 * 2, 8 * 2); + r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); + + if (!(c & 0x80)) { + // Blink text. We subtract _startMillis to make this compatible + // with the event recorder, which returns offsetted values on + // playback. + const uint32 millisPassed = g_system->getMillis() - _startMillis; + if (!(c & 0x40) || ((millisPassed / 270) & 1)) + r.translate(0, 4 * 8 * 2); + } + + _textSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r); + } +} + +void Display_A2::drawChar(byte c, int x, int y) { + byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x; + + for (uint row = 0; row < 8; ++row) { + for (uint col = 1; col < 6; ++col) { + if (font[c][col - 1] & (1 << row)) { + buf[col * 2] = 1; + buf[col * 2 + 1] = 1; + } + } + + buf += 2 * _font->pitch; + } +} + +void Display_A2::createFont() { + _font = new Graphics::Surface; + _font->create(16 * 7 * 2, 4 * 8 * 2 * 2, Graphics::PixelFormat::createFormatCLUT8()); + + for (uint i = 0; i < 4; ++i) + for (uint j = 0; j < 16; ++j) + drawChar(i * 16 + j, j * 7 * 2, i * 8 * 2); + + // Create inverted font + byte *buf = (byte *)_font->getPixels(); + byte *bufInv = buf + (_font->h / 2) * _font->pitch; + + for (uint row = 0; row < _font->h / 2; row += 2) { + for (uint col = 0; col < _font->w; ++col) + bufInv[col] = (buf[col] ? 0 : 1); + + buf += _font->pitch * 2; + bufInv += _font->pitch * 2; + } + + copyEvenSurfaceRows(*_font); +} + +} // End of namespace Adl diff --git a/engines/adl/display_a2.h b/engines/adl/display_a2.h new file mode 100644 index 0000000000..5823c2410b --- /dev/null +++ b/engines/adl/display_a2.h @@ -0,0 +1,85 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "adl/display.h" + +#ifndef ADL_DISPLAY_A2_H +#define ADL_DISPLAY_A2_H + +namespace Adl { + +class Display_A2 : public Display { +public: + Display_A2(); + virtual ~Display_A2(); + + enum { + kGfxWidth = 280, + kGfxHeight = 192, + kGfxPitch = kGfxWidth / 7, + kGfxSize = kGfxWidth * kGfxHeight, + kTextWidth = 40, + kTextHeight = 24 + }; + + virtual void init() override; + virtual bool saveThumbnail(Common::WriteStream &out) override; + + // Graphics + uint getGfxWidth() const { return kGfxWidth; } + uint getGfxHeight() const { return kGfxHeight; } + uint getGfxPitch() const { return kGfxPitch; } + void loadFrameBuffer(Common::ReadStream &stream, byte *dst); + void loadFrameBuffer(Common::ReadStream &stream); + void putPixel(const Common::Point &p, byte color); + void setPixelByte(const Common::Point &p, byte color); + void setPixelBit(const Common::Point &p, byte color); + void setPixelPalette(const Common::Point &p, byte color); + byte getPixelByte(const Common::Point &p) const; + bool getPixelBit(const Common::Point &p) const; + void clear(byte color); + + // Text + virtual char asciiToNative(char c) const override { return c | 0x80; } + virtual void printChar(char c) override; + virtual void showCursor(bool enable); + +private: + void writeFrameBuffer(const Common::Point &p, byte color, byte mask); + virtual void updateTextSurface() override; + virtual void updateGfxSurface() override; + + void showScanlines(bool enable); + void drawChar(byte c, int x, int y); + void createFont(); + + byte *_frameBuf; + bool _scanlines; + bool _monochrome; + Graphics::Surface *_font; + bool _showCursor; + uint32 _startMillis; +}; + +} // End of namespace Adl + +#endif diff --git a/engines/adl/graphics.cpp b/engines/adl/graphics.cpp deleted file mode 100644 index 2fcd1473a0..0000000000 --- a/engines/adl/graphics.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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. - * - */ - -#include "common/stream.h" -#include "common/rect.h" -#include "common/textconsole.h" - -#include "adl/display.h" -#include "adl/graphics.h" - -namespace Adl { - -void GraphicsMan::clearScreen() const { - _display.setMode(DISPLAY_MODE_MIXED); - _display.clear(getClearColor()); -} - -// Draws a four-connected line -void GraphicsMan::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const { - int16 deltaX = p2.x - p1.x; - int8 xStep = 1; - - if (deltaX < 0) { - deltaX = -deltaX; - xStep = -1; - } - - int16 deltaY = p2.y - p1.y; - int8 yStep = -1; - - if (deltaY > 0) { - deltaY = -deltaY; - yStep = 1; - } - - Common::Point p(p1); - int16 steps = deltaX - deltaY + 1; - int16 err = deltaX + deltaY; - - while (true) { - putPixel(p, color); - - if (--steps == 0) - return; - - if (err < 0) { - p.y += yStep; - err += deltaX; - } else { - p.x += xStep; - err += deltaY; - } - } -} - -void GraphicsMan::putPixel(const Common::Point &p, byte color) const { - if (_bounds.contains(p)) - _display.putPixel(p, color); -} - -void GraphicsMan::drawShapePixel(Common::Point &p, byte color, byte bits, byte quadrant) const { - if (bits & 4) - putPixel(p, color); - - bits += quadrant; - - if (bits & 1) - p.x += (bits & 2 ? -1 : 1); - else - p.y += (bits & 2 ? 1 : -1); -} - -void GraphicsMan::drawShape(Common::ReadStream &corners, Common::Point &pos, byte rotation, byte scaling, byte color) const { - const byte stepping[] = { - 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, - 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, - 0xff - }; - - byte quadrant = rotation >> 4; - rotation &= 0xf; - byte xStep = stepping[rotation]; - byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; - - while (true) { - byte b = corners.readByte(); - - if (corners.eos() || corners.err()) - error("Error reading corners"); - - if (b == 0) - return; - - do { - byte xFrac = 0x80; - byte yFrac = 0x80; - for (uint j = 0; j < scaling; ++j) { - if (xFrac + xStep + 1 > 255) - drawShapePixel(pos, color, b, quadrant); - xFrac += xStep + 1; - if (yFrac + yStep > 255) - drawShapePixel(pos, color, b, quadrant + 1); - yFrac += yStep; - } - b >>= 3; - } while (b != 0); - } -} - -void GraphicsMan::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) { - byte x, y; - bool bNewLine = false; - byte oldX = 0, oldY = 0; - while (1) { - x = pic.readByte(); - y = pic.readByte(); - - if (pic.err() || pic.eos()) - error("Error reading picture"); - - if (x == 0xff && y == 0xff) - return; - - if (x == 0 && y == 0) { - bNewLine = true; - continue; - } - - x += pos.x; - y += pos.y; - - if (y > 160) - y = 160; - - if (bNewLine) { - putPixel(Common::Point(x, y), 0x7f); - bNewLine = false; - } else { - drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); - } - - oldX = x; - oldY = y; - } -} - -#define NUM_PATTERNS 22 -#define PATTERN_LEN 4 -static const byte fillPatterns[NUM_PATTERNS][PATTERN_LEN] = { - { 0x00, 0x00, 0x00, 0x00 }, - { 0x80, 0x80, 0x80, 0x80 }, - { 0xff, 0xff, 0xff, 0xff }, - { 0x7f, 0x7f, 0x7f, 0x7f }, - { 0x2a, 0x55, 0x2a, 0x55 }, - { 0xaa, 0xd5, 0xaa, 0xd5 }, - { 0x55, 0x2a, 0x55, 0x2a }, - { 0xd5, 0xaa, 0xd5, 0xaa }, - { 0x33, 0x66, 0x4c, 0x19 }, - { 0xb3, 0xe6, 0xcc, 0x99 }, - { 0x22, 0x44, 0x08, 0x11 }, - { 0xa2, 0xc4, 0x88, 0x91 }, - { 0x11, 0x22, 0x44, 0x08 }, - { 0x91, 0xa2, 0xc4, 0x88 }, - { 0x6e, 0x5d, 0x3b, 0x77 }, - { 0xee, 0xdd, 0xbb, 0xf7 }, - { 0x5d, 0x3b, 0x77, 0x6e }, - { 0xdd, 0xbb, 0xf7, 0xee }, - { 0x66, 0x4c, 0x19, 0x33 }, - { 0xe6, 0xcc, 0x99, 0xb3 }, - { 0x33, 0x66, 0x4c, 0x19 }, - { 0xb3, 0xe6, 0xcc, 0x99 } -}; - -#define MIN_COMMAND 0xe0 - -#define CHECK_COMMAND(X) \ - do { \ - if ((X) >= MIN_COMMAND) { \ - pic.seek(-1, SEEK_CUR); \ - return; \ - } \ - } while (0) - -#define READ_BYTE(b) \ - do { \ - b = pic.readByte(); \ - if (pic.eos() || pic.err()) \ - error("Error reading picture"); \ - CHECK_COMMAND(b); \ - } while (0) - -#define READ_POINT(p) \ - do { \ - READ_BYTE(p.x); \ - p.x += _offset.x; \ - p.x <<= 1; \ - READ_BYTE(p.y); \ - p.y += _offset.y; \ - } while (0) - -void GraphicsMan_v2::drawCorners(Common::SeekableReadStream &pic, bool yFirst) { - Common::Point p; - - READ_POINT(p); - - if (yFirst) - goto doYStep; - - while (true) { - int16 n; - - READ_BYTE(n); - n += _offset.x; - - putPixel(p, _color); - - n <<= 1; - drawLine(p, Common::Point(n, p.y), _color); - p.x = n; - -doYStep: - READ_BYTE(n); - n += _offset.y; - - putPixel(p, _color); - drawLine(p, Common::Point(p.x, n), _color); - - putPixel(Common::Point(p.x + 1, p.y), _color); - drawLine(Common::Point(p.x + 1, p.y), Common::Point(p.x + 1, n), _color); - - p.y = n; - } -} - -void GraphicsMan_v2::drawRelativeLines(Common::SeekableReadStream &pic) { - Common::Point p1; - - READ_POINT(p1); - putPixel(p1, _color); - - while (true) { - Common::Point p2(p1); - - byte n; - READ_BYTE(n); - - byte h = (n & 0x70) >> 4; - byte l = n & 7; - - if (n & 0x80) - p2.x -= (h << 1); - else - p2.x += (h << 1); - - if (n & 8) - p2.y -= l; - else - p2.y += l; - - drawLine(p1, p2, _color); - p1 = p2; - } -} - -void GraphicsMan_v2::drawAbsoluteLines(Common::SeekableReadStream &pic) { - Common::Point p1; - - READ_POINT(p1); - putPixel(p1, _color); - - while (true) { - Common::Point p2; - - READ_POINT(p2); - drawLine(p1, p2, _color); - p1 = p2; - } -} - -static byte getPatternColor(const Common::Point &p, byte pattern) { - if (pattern >= NUM_PATTERNS) - error("Invalid fill pattern %i encountered in picture", pattern); - - byte offset = (p.y & 1) << 1; - offset += (p.x / 7) & 3; - - return fillPatterns[pattern][offset % PATTERN_LEN]; -} - -bool GraphicsMan_v2::canFillAt(const Common::Point &p, const bool stopBit) { - return _display.getPixelBit(p) != stopBit && _display.getPixelBit(Common::Point(p.x + 1, p.y)) != stopBit; -} - -void GraphicsMan_v2::fillRowLeft(Common::Point p, const byte pattern, const bool stopBit) { - byte color = getPatternColor(p, pattern); - - while (--p.x >= _bounds.left) { - if ((p.x % 7) == 6) { - color = getPatternColor(p, pattern); - _display.setPixelPalette(p, color); - } - if (_display.getPixelBit(p) == stopBit) - break; - _display.setPixelBit(p, color); - } -} - -void GraphicsMan_v2::fillRow(Common::Point p, const byte pattern, const bool stopBit) { - // Set pixel at p and palette - byte color = getPatternColor(p, pattern); - _display.setPixelPalette(p, color); - _display.setPixelBit(p, color); - - // Fill left of p - fillRowLeft(p, pattern, stopBit); - - // Fill right of p - while (++p.x < _bounds.right) { - if ((p.x % 7) == 0) { - color = getPatternColor(p, pattern); - // Palette is set before the first bit is tested - _display.setPixelPalette(p, color); - } - if (_display.getPixelBit(p) == stopBit) - break; - _display.setPixelBit(p, color); - } -} - -void GraphicsMan_v2::fillAt(Common::Point p, const byte pattern) { - const bool stopBit = !_display.getPixelBit(p); - - // Move up into the open space above p - while (--p.y >= _bounds.top && canFillAt(p, stopBit)) {} - - // Then fill by moving down - while (++p.y < _bounds.bottom && canFillAt(p, stopBit)) - fillRow(p, pattern, stopBit); -} - -void GraphicsMan_v2::fill(Common::SeekableReadStream &pic) { - byte pattern; - READ_BYTE(pattern); - - while (true) { - Common::Point p; - READ_POINT(p); - - if (_bounds.contains(p)) - fillAt(p, pattern); - } -} - -void GraphicsMan_v2::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) { - // NOTE: The original engine only resets the color for overlays. As a result, room - // pictures that draw without setting a color or clearing the screen, will use the - // last color set by the previous picture. We assume this is unintentional and do - // not copy this behavior. - _color = 0; - _offset = pos; - - while (true) { - byte opcode = pic.readByte(); - - if (pic.eos() || pic.err()) - error("Error reading picture"); - - switch (opcode) { - case 0xe0: - drawCorners(pic, false); - break; - case 0xe1: - drawCorners(pic, true); - break; - case 0xe2: - drawRelativeLines(pic); - break; - case 0xe3: - drawAbsoluteLines(pic); - break; - case 0xe4: - fill(pic); - break; - case 0xe5: - clearScreen(); - _color = 0x00; - break; - case 0xf0: - _color = 0x00; - break; - case 0xf1: - _color = 0x2a; - break; - case 0xf2: - _color = 0x55; - break; - case 0xf3: - _color = 0x7f; - break; - case 0xf4: - _color = 0x80; - break; - case 0xf5: - _color = 0xaa; - break; - case 0xf6: - _color = 0xd5; - break; - case 0xf7: - _color = 0xff; - break; - case 0xff: - return; - default: - if (opcode >= 0xe0) - error("Invalid pic opcode %02x", opcode); - else - warning("Expected pic opcode, but found data byte %02x", opcode); - } - } -} - -void GraphicsMan_v3::fillRowLeft(Common::Point p, const byte pattern, const bool stopBit) { - byte color = getPatternColor(p, pattern); - - while (--p.x >= _bounds.left) { - // In this version, when moving left, it no longer sets the palette first - if (!_display.getPixelBit(p)) - return; - if ((p.x % 7) == 6) { - color = getPatternColor(p, pattern); - _display.setPixelPalette(p, color); - } - _display.setPixelBit(p, color); - } -} - -void GraphicsMan_v3::fillAt(Common::Point p, const byte pattern) { - // If the row at p cannot be filled, we do nothing - if (!canFillAt(p)) - return; - - fillRow(p, pattern); - - Common::Point q(p); - - // Fill up from p - while (--q.y >= _bounds.top && canFillAt(q)) - fillRow(q, pattern); - - // Fill down from p - while (++p.y < _bounds.bottom && canFillAt(p)) - fillRow(p, pattern); -} - -} // End of namespace Adl diff --git a/engines/adl/graphics.h b/engines/adl/graphics.h index 38dc2b25aa..ad56281598 100644 --- a/engines/adl/graphics.h +++ b/engines/adl/graphics.h @@ -24,34 +24,44 @@ #define ADL_GRAPHICS_H #include "common/rect.h" +#include "common/stream.h" -namespace Common { -class SeekableReadStream; -} +#include "adl/display.h" namespace Adl { -class Display; - -// Used in hires1 class GraphicsMan { public: - GraphicsMan(Display &display) : _bounds(280, 160), _display(display) { } virtual ~GraphicsMan() { } // Applesoft BASIC HLINE - void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const; + virtual void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const = 0; // Applesoft BASIC DRAW - void drawShape(Common::ReadStream &shape, Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const; - - virtual void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos); - void clearScreen() const; - void putPixel(const Common::Point &p, byte color) const; + virtual void drawShape(Common::ReadStream &shape, Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const = 0; + virtual void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) = 0; + virtual void clearScreen() const = 0; void setBounds(const Common::Rect &r) { _bounds = r; } protected: - Display &_display; Common::Rect _bounds; +}; + +// Used in hires1 +template +class GraphicsMan_v1 : public GraphicsMan { +public: + using GraphicsMan::_bounds; + + GraphicsMan_v1(T &display) : _display(display) { this->setBounds(Common::Rect(280, 160)); } + + virtual void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const override; + virtual void drawShape(Common::ReadStream &shape, Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const override; + virtual void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) override; + virtual void clearScreen() const override; + +protected: + T &_display; + void putPixel(const Common::Point &p, byte color) const; private: void drawShapePixel(Common::Point &p, byte color, byte bits, byte quadrant) const; @@ -59,38 +69,537 @@ private: }; // Used in hires0 and hires2-hires4 -class GraphicsMan_v2 : public GraphicsMan { +template +class GraphicsMan_v2 : public GraphicsMan_v1 { public: - GraphicsMan_v2(Display &display) : GraphicsMan(display), _color(0) { } + using GraphicsMan::_bounds; + using GraphicsMan_v1::_display; + using GraphicsMan_v1::drawLine; + using GraphicsMan_v1::putPixel; + + GraphicsMan_v2(T &display) : GraphicsMan_v1(display), _color(0) { } void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos); protected: bool canFillAt(const Common::Point &p, const bool stopBit = false); void fillRow(Common::Point p, const byte pattern, const bool stopBit = false); + byte getPatternColor(const Common::Point &p, byte pattern); private: + static bool readByte(Common::SeekableReadStream &pic, byte &b); + bool readPoint(Common::SeekableReadStream &pic, Common::Point &p); void drawCorners(Common::SeekableReadStream &pic, bool yFirst); void drawRelativeLines(Common::SeekableReadStream &pic); void drawAbsoluteLines(Common::SeekableReadStream &pic); + void fill(Common::SeekableReadStream &pic); virtual void fillRowLeft(Common::Point p, const byte pattern, const bool stopBit); virtual void fillAt(Common::Point p, const byte pattern); - void fill(Common::SeekableReadStream &pic); - byte getClearColor() const { return 0xff; } + virtual byte getClearColor() const override { return 0xff; } byte _color; Common::Point _offset; }; // Used in hires5, hires6 and gelfling (possibly others as well) -class GraphicsMan_v3 : public GraphicsMan_v2 { +template +class GraphicsMan_v3 : public GraphicsMan_v2 { public: - GraphicsMan_v3(Display &display) : GraphicsMan_v2(display) { } + using GraphicsMan::_bounds; + using GraphicsMan_v1::_display; + using GraphicsMan_v2::canFillAt; + using GraphicsMan_v2::fillRow; + using GraphicsMan_v2::getPatternColor; + + GraphicsMan_v3(T &display) : GraphicsMan_v2(display) { } private: - void fillRowLeft(Common::Point p, const byte pattern, const bool stopBit); - void fillAt(Common::Point p, const byte pattern); + virtual void fillRowLeft(Common::Point p, const byte pattern, const bool stopBit) override; + virtual void fillAt(Common::Point p, const byte pattern) override; }; +template +void GraphicsMan_v1::clearScreen() const { + _display.setMode(Display::kModeMixed); + _display.clear(getClearColor()); +} + +// Draws a four-connected line +template +void GraphicsMan_v1::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const { + int16 deltaX = p2.x - p1.x; + int8 xStep = 1; + + if (deltaX < 0) { + deltaX = -deltaX; + xStep = -1; + } + + int16 deltaY = p2.y - p1.y; + int8 yStep = -1; + + if (deltaY > 0) { + deltaY = -deltaY; + yStep = 1; + } + + Common::Point p(p1); + int16 steps = deltaX - deltaY + 1; + int16 err = deltaX + deltaY; + + while (true) { + putPixel(p, color); + + if (--steps == 0) + return; + + if (err < 0) { + p.y += yStep; + err += deltaX; + } else { + p.x += xStep; + err += deltaY; + } + } +} + +template +void GraphicsMan_v1::putPixel(const Common::Point &p, byte color) const { + if (_bounds.contains(p)) + _display.putPixel(p, color); +} + +template +void GraphicsMan_v1::drawShapePixel(Common::Point &p, byte color, byte bits, byte quadrant) const { + if (bits & 4) + putPixel(p, color); + + bits += quadrant; + + if (bits & 1) + p.x += (bits & 2 ? -1 : 1); + else + p.y += (bits & 2 ? 1 : -1); +} + +template +void GraphicsMan_v1::drawShape(Common::ReadStream &corners, Common::Point &pos, byte rotation, byte scaling, byte color) const { + const byte stepping[] = { + 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5, + 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18, + 0xff + }; + + byte quadrant = rotation >> 4; + rotation &= 0xf; + byte xStep = stepping[rotation]; + byte yStep = stepping[(rotation ^ 0xf) + 1] + 1; + + while (true) { + byte b = corners.readByte(); + + if (corners.eos() || corners.err()) + error("Error reading corners"); + + if (b == 0) + return; + + do { + byte xFrac = 0x80; + byte yFrac = 0x80; + for (uint j = 0; j < scaling; ++j) { + if (xFrac + xStep + 1 > 255) + drawShapePixel(pos, color, b, quadrant); + xFrac += xStep + 1; + if (yFrac + yStep > 255) + drawShapePixel(pos, color, b, quadrant + 1); + yFrac += yStep; + } + b >>= 3; + } while (b != 0); + } +} + +template +void GraphicsMan_v1::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) { + byte x, y; + bool bNewLine = false; + byte oldX = 0, oldY = 0; + while (1) { + x = pic.readByte(); + y = pic.readByte(); + + if (pic.err() || pic.eos()) + error("Error reading picture"); + + if (x == 0xff && y == 0xff) + return; + + if (x == 0 && y == 0) { + bNewLine = true; + continue; + } + + x += pos.x; + y += pos.y; + + if (y > 160) + y = 160; + + if (bNewLine) { + putPixel(Common::Point(x, y), 0x7f); + bNewLine = false; + } else { + drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f); + } + + oldX = x; + oldY = y; + } +} + +template +bool GraphicsMan_v2::readByte(Common::SeekableReadStream &pic, byte &b) { + b = pic.readByte(); + + if (pic.eos() || pic.err()) + error("Error reading picture"); + + if (b >= 0xe0) { + pic.seek(-1, SEEK_CUR); + return false; + } + + return true; +} + +template +bool GraphicsMan_v2::readPoint(Common::SeekableReadStream &pic, Common::Point &p) { + byte b; + + if (!readByte(pic, b)) + return false; + + p.x = b + _offset.x; + p.x <<= 1; + + if (!readByte(pic, b)) + return false; + + p.y = b + _offset.y; + + return true; +} + +template +byte GraphicsMan_v2::getPatternColor(const Common::Point &p, byte pattern) { + const byte fillPatterns[][4] = { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x80, 0x80, 0x80, 0x80 }, + { 0xff, 0xff, 0xff, 0xff }, + { 0x7f, 0x7f, 0x7f, 0x7f }, + { 0x2a, 0x55, 0x2a, 0x55 }, + { 0xaa, 0xd5, 0xaa, 0xd5 }, + { 0x55, 0x2a, 0x55, 0x2a }, + { 0xd5, 0xaa, 0xd5, 0xaa }, + { 0x33, 0x66, 0x4c, 0x19 }, + { 0xb3, 0xe6, 0xcc, 0x99 }, + { 0x22, 0x44, 0x08, 0x11 }, + { 0xa2, 0xc4, 0x88, 0x91 }, + { 0x11, 0x22, 0x44, 0x08 }, + { 0x91, 0xa2, 0xc4, 0x88 }, + { 0x6e, 0x5d, 0x3b, 0x77 }, + { 0xee, 0xdd, 0xbb, 0xf7 }, + { 0x5d, 0x3b, 0x77, 0x6e }, + { 0xdd, 0xbb, 0xf7, 0xee }, + { 0x66, 0x4c, 0x19, 0x33 }, + { 0xe6, 0xcc, 0x99, 0xb3 }, + { 0x33, 0x66, 0x4c, 0x19 }, + { 0xb3, 0xe6, 0xcc, 0x99 } + }; + + if (pattern >= ARRAYSIZE(fillPatterns)) + error("Invalid fill pattern %i encountered in picture", pattern); + + byte offset = (p.y & 1) << 1; + offset += (p.x / 7) & 3; + + return fillPatterns[pattern][offset % sizeof(fillPatterns[0])]; +} + +template +void GraphicsMan_v2::drawCorners(Common::SeekableReadStream &pic, bool yFirst) { + Common::Point p; + + if (!readPoint(pic, p)) + return; + + if (yFirst) + goto doYStep; + + while (true) { + byte b; + int16 n; + + if (!readByte(pic, b)) + return; + + n = b + _offset.x; + + putPixel(p, _color); + + n <<= 1; + drawLine(p, Common::Point(n, p.y), _color); + p.x = n; + +doYStep: + if (!readByte(pic, b)) + return; + + n = b + _offset.y; + + putPixel(p, _color); + drawLine(p, Common::Point(p.x, n), _color); + + putPixel(Common::Point(p.x + 1, p.y), _color); + drawLine(Common::Point(p.x + 1, p.y), Common::Point(p.x + 1, n), _color); + + p.y = n; + } +} + +template +void GraphicsMan_v2::drawRelativeLines(Common::SeekableReadStream &pic) { + Common::Point p1; + + if (!readPoint(pic, p1)) + return; + + putPixel(p1, _color); + + while (true) { + Common::Point p2(p1); + + byte n; + + if (!readByte(pic, n)) + return; + + byte h = (n & 0x70) >> 4; + byte l = n & 7; + + if (n & 0x80) + p2.x -= (h << 1); + else + p2.x += (h << 1); + + if (n & 8) + p2.y -= l; + else + p2.y += l; + + drawLine(p1, p2, _color); + p1 = p2; + } +} + +template +void GraphicsMan_v2::drawAbsoluteLines(Common::SeekableReadStream &pic) { + Common::Point p1; + + if (!readPoint(pic, p1)) + return; + + putPixel(p1, _color); + + while (true) { + Common::Point p2; + + if (!readPoint(pic, p2)) + return; + + drawLine(p1, p2, _color); + p1 = p2; + } +} + +template +bool GraphicsMan_v2::canFillAt(const Common::Point &p, const bool stopBit) { + return _display.getPixelBit(p) != stopBit && _display.getPixelBit(Common::Point(p.x + 1, p.y)) != stopBit; +} + +template +void GraphicsMan_v2::fillRowLeft(Common::Point p, const byte pattern, const bool stopBit) { + byte color = getPatternColor(p, pattern); + + while (--p.x >= _bounds.left) { + if ((p.x % 7) == 6) { + color = getPatternColor(p, pattern); + _display.setPixelPalette(p, color); + } + if (_display.getPixelBit(p) == stopBit) + break; + _display.setPixelBit(p, color); + } +} + +template +void GraphicsMan_v2::fillRow(Common::Point p, const byte pattern, const bool stopBit) { + // Set pixel at p and palette + byte color = getPatternColor(p, pattern); + _display.setPixelPalette(p, color); + _display.setPixelBit(p, color); + + // Fill left of p + fillRowLeft(p, pattern, stopBit); + + // Fill right of p + while (++p.x < _bounds.right) { + if ((p.x % 7) == 0) { + color = getPatternColor(p, pattern); + // Palette is set before the first bit is tested + _display.setPixelPalette(p, color); + } + if (_display.getPixelBit(p) == stopBit) + break; + _display.setPixelBit(p, color); + } +} + +template +void GraphicsMan_v2::fillAt(Common::Point p, const byte pattern) { + const bool stopBit = !_display.getPixelBit(p); + + // Move up into the open space above p + while (--p.y >= _bounds.top && canFillAt(p, stopBit)) {} + + // Then fill by moving down + while (++p.y < _bounds.bottom && canFillAt(p, stopBit)) + fillRow(p, pattern, stopBit); +} + +template +void GraphicsMan_v2::fill(Common::SeekableReadStream &pic) { + byte pattern; + + if (!readByte(pic, pattern)) + return; + + while (true) { + Common::Point p; + + if (!readPoint(pic, p)) + return; + + if (_bounds.contains(p)) + fillAt(p, pattern); + } +} + +template +void GraphicsMan_v2::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) { + // NOTE: The original engine only resets the color for overlays. As a result, room + // pictures that draw without setting a color or clearing the screen, will use the + // last color set by the previous picture. We assume this is unintentional and do + // not copy this behavior. + _color = 0; + _offset = pos; + + while (true) { + byte opcode = pic.readByte(); + + if (pic.eos() || pic.err()) + error("Error reading picture"); + + switch (opcode) { + case 0xe0: + drawCorners(pic, false); + break; + case 0xe1: + drawCorners(pic, true); + break; + case 0xe2: + drawRelativeLines(pic); + break; + case 0xe3: + drawAbsoluteLines(pic); + break; + case 0xe4: + fill(pic); + break; + case 0xe5: + this->clearScreen(); + _color = 0x00; + break; + case 0xf0: + _color = 0x00; + break; + case 0xf1: + _color = 0x2a; + break; + case 0xf2: + _color = 0x55; + break; + case 0xf3: + _color = 0x7f; + break; + case 0xf4: + _color = 0x80; + break; + case 0xf5: + _color = 0xaa; + break; + case 0xf6: + _color = 0xd5; + break; + case 0xf7: + _color = 0xff; + break; + case 0xff: + return; + default: + if (opcode >= 0xe0) + error("Invalid pic opcode %02x", opcode); + else + warning("Expected pic opcode, but found data byte %02x", opcode); + } + } +} + +template +void GraphicsMan_v3::fillRowLeft(Common::Point p, const byte pattern, const bool stopBit) { + byte color = getPatternColor(p, pattern); + + while (--p.x >= _bounds.left) { + // In this version, when moving left, it no longer sets the palette first + if (!_display.getPixelBit(p)) + return; + if ((p.x % 7) == 6) { + color = getPatternColor(p, pattern); + _display.setPixelPalette(p, color); + } + _display.setPixelBit(p, color); + } +} + +template +void GraphicsMan_v3::fillAt(Common::Point p, const byte pattern) { + // If the row at p cannot be filled, we do nothing + if (!canFillAt(p)) + return; + + fillRow(p, pattern); + + Common::Point q(p); + + // Fill up from p + while (--q.y >= _bounds.top && canFillAt(q)) + fillRow(q, pattern); + + // Fill down from p + while (++p.y < _bounds.bottom && canFillAt(p)) + fillRow(p, pattern); +} + } // End of namespace Adl #endif diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 2cf2931896..c045ce94ad 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -29,7 +29,7 @@ #include "adl/adl.h" #include "adl/graphics.h" -#include "adl/display.h" +#include "adl/display_a2.h" namespace Adl { @@ -126,7 +126,7 @@ private: }; void HiRes1Engine::showInstructions(Common::SeekableReadStream &stream, const uint pages[], bool goHome) { - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); uint page = 0; while (pages[page] != 0) { @@ -154,9 +154,9 @@ void HiRes1Engine::runIntro() { // Early version have no bitmap in 'AUTO LOAD OBJ' if (getGameVersion() >= GAME_VER_HR1_COARSE) { stream->seek(IDI_HR1_OFS_LOGO_0); - _display->setMode(DISPLAY_MODE_HIRES); - _display->loadFrameBuffer(*stream); - _display->updateHiResScreen(); + _display->setMode(Display::kModeGraphics); + static_cast(_display)->loadFrameBuffer(*stream); + _display->copyGfxSurface(); if (getGameVersion() == GAME_VER_HR1_PD) { // Only the PD version shows a title screen during the load @@ -177,7 +177,7 @@ void HiRes1Engine::runIntro() { // was present in the original PD release back in 1987. StreamPtr basic(_files->createReadStream("MYSTERY.HELLO")); - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); _display->home(); str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_0, '"'); @@ -197,7 +197,7 @@ void HiRes1Engine::runIntro() { return; } - _display->setMode(DISPLAY_MODE_MIXED); + _display->setMode(Display::kModeMixed); str = readStringAt(*stream, IDI_HR1_OFS_GAME_OR_HELP); @@ -238,10 +238,10 @@ void HiRes1Engine::runIntro() { stream.reset(_files->createReadStream(IDS_HR1_EXE_1)); stream->seek(0x1800); - _display->loadFrameBuffer(*stream); - _display->updateHiResScreen(); + static_cast(_display)->loadFrameBuffer(*stream); + _display->copyGfxSurface(); - _display->setMode(DISPLAY_MODE_MIXED); + _display->setMode(Display::kModeMixed); if (getGameVersion() == GAME_VER_HR1_SIMI) { // The original waits for the key after initializing the state. @@ -268,7 +268,7 @@ void HiRes1Engine::init() { _files = files; } - _graphics = new GraphicsMan(*_display); + _graphics = new GraphicsMan_v1(*static_cast(_display)); _display->moveCursorTo(Common::Point(0, 3)); StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1)); @@ -478,7 +478,7 @@ void HiRes1Engine::showRoom() { drawItems(); } - _display->updateHiResScreen(); + _display->copyGfxSurface(); _messageDelay = false; printString(_roomData.description); _messageDelay = true; diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp index 4575cf6854..4dbda103fe 100644 --- a/engines/adl/hires2.cpp +++ b/engines/adl/hires2.cpp @@ -27,7 +27,7 @@ #include "common/stream.h" #include "adl/adl_v2.h" -#include "adl/display.h" +#include "adl/display_a2.h" #include "adl/graphics.h" #include "adl/disk.h" @@ -59,7 +59,7 @@ HiResBaseEngine::HiResBaseEngine(OSystem *syst, const AdlGameDescription *gd, co } void HiResBaseEngine::init() { - _graphics = new GraphicsMan_v2(*_display); + _graphics = new GraphicsMan_v2(*static_cast(_display)); _disk = new DiskImage(); if (!_disk->open(getDiskImageName(0))) @@ -157,7 +157,7 @@ void HiRes2Engine::runIntro() { _disk->setSectorLimit(0); StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1)); - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); Common::String str = readString(*stream); diff --git a/engines/adl/hires4.cpp b/engines/adl/hires4.cpp index ef1b1846d0..d914661f37 100644 --- a/engines/adl/hires4.cpp +++ b/engines/adl/hires4.cpp @@ -30,7 +30,7 @@ #include "adl/adl_v3.h" #include "adl/detection.h" -#include "adl/display.h" +#include "adl/display_a2.h" #include "adl/graphics.h" #include "adl/disk.h" @@ -134,7 +134,7 @@ void HiRes4Engine::putSpace(uint x, uint y) const { _display->moveCursorTo(Common::Point(x, y)); _display->printChar(' '); - _display->updateTextScreen(); + _display->copyTextSurface(); delay(2); } @@ -167,7 +167,7 @@ void HiRes4Engine::drawText(const Common::String &str, Common::SeekableReadStrea drawChar(c, shapeTable, pos); drawChar(98, shapeTable, pos); - _display->updateHiResScreen(); + _display->copyGfxSurface(); delay(15); } } @@ -179,7 +179,7 @@ void HiRes4Engine::runIntroAdvise(Common::SeekableReadStream &menu) { backupText.push_back(readStringAt(menu, 0x6a9, '"')); backupText.push_back(readStringAt(menu, 0x6c6, '"')); - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); for (uint x = 2; x <= 36; ++x) putSpace(x, 2); @@ -223,7 +223,7 @@ void HiRes4Engine::runIntroAdvise(Common::SeekableReadStream &menu) { _display->printAsciiString(left); _display->moveCursorTo(Common::Point(19, y)); _display->printAsciiString(right); - _display->updateTextScreen(); + _display->copyTextSurface(); delay(35); } while (x != backupText[i].size() / 2); @@ -245,26 +245,31 @@ void HiRes4Engine::runIntroAdvise(Common::SeekableReadStream &menu) { _display->moveCursorTo(Common::Point(32, 18)); _display->printChar(APPLECHAR(cursor[cursorIdx])); - _display->updateTextScreen(); + _display->copyTextSurface(); g_system->delayMillis(25); cursorIdx = (cursorIdx + 1) % cursor.size(); } } void HiRes4Engine::runIntroLogo(Common::SeekableReadStream &ms2) { - _display->clear(0x00); - _display->setMode(DISPLAY_MODE_HIRES); - byte *logo = new byte[DISPLAY_SIZE]; - Display::loadFrameBuffer(ms2, logo); - - for (uint x = 0; x < DISPLAY_WIDTH; ++x) { - for (uint y = 0; y < DISPLAY_HEIGHT; ++y) { - const byte p = logo[y * DISPLAY_PITCH + x / 7]; - _display->setPixelBit(Common::Point(x, y), p); + Display_A2 *display = static_cast(_display); + const uint width = display->getGfxWidth(); + const uint height = display->getGfxHeight(); + const uint pitch = display->getGfxPitch(); + + display->clear(0x00); + display->setMode(Display::kModeGraphics); + byte *logo = new byte[pitch * height]; + display->loadFrameBuffer(ms2, logo); + + for (uint x = 0; x < width; ++x) { + for (uint y = 0; y < height; ++y) { + const byte p = logo[y * pitch + x / 7]; + display->setPixelBit(Common::Point(x, y), p); if (x % 7 == 6) - _display->setPixelPalette(Common::Point(x, y), p); + display->setPixelPalette(Common::Point(x, y), p); } - _display->updateHiResScreen(); + display->copyGfxSurface(); if (shouldQuit()) { delete[] logo; @@ -279,11 +284,11 @@ void HiRes4Engine::runIntroLogo(Common::SeekableReadStream &ms2) { for (uint i = 38; i != 0; --i) { Common::Point p; - for (p.y = 1; p.y < DISPLAY_HEIGHT; ++p.y) - for (p.x = 0; p.x < DISPLAY_WIDTH; p.x += 7) - _display->setPixelByte(Common::Point(p.x, p.y - 1), _display->getPixelByte(p)); + for (p.y = 1; p.y < (int)height; ++p.y) + for (p.x = 0; p.x < (int)width; p.x += 7) + display->setPixelByte(Common::Point(p.x, p.y - 1), display->getPixelByte(p)); - _display->updateHiResScreen(); + display->copyGfxSurface(); Tones tone; tone.push_back(Tone(kClock / 2.0 / ((i * 4 + 1) * 10.0 + 10.0), 12.5)); @@ -309,13 +314,13 @@ void HiRes4Engine::runIntroTitle(Common::SeekableReadStream &menu, Common::Seeka // Draw "TM" with lines _graphics->drawLine(Common::Point(200, 170), Common::Point(200, 174), 0x7f); _graphics->drawLine(Common::Point(198, 170), Common::Point(202, 170), 0x7f); - _display->updateHiResScreen(); + _display->copyGfxSurface(); delay(7); _graphics->drawLine(Common::Point(204, 170), Common::Point(204, 174), 0x7f); _graphics->drawLine(Common::Point(204, 170), Common::Point(207, 173), 0x7f); _graphics->drawLine(Common::Point(207, 173), Common::Point(209, 170), 0x7f); _graphics->drawLine(Common::Point(209, 170), Common::Point(209, 174), 0x7f); - _display->updateHiResScreen(); + _display->copyGfxSurface(); delay(7); titleString = readStringAt(menu, 0x46c); @@ -341,7 +346,7 @@ void HiRes4Engine::runIntroInstructions(Common::SeekableReadStream &instructions instructions.seek(0); _display->home(); - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); // Search for PRINT commands in tokenized BASIC while (1) { @@ -397,7 +402,7 @@ void HiRes4Engine::runIntroInstructions(Common::SeekableReadStream &instructions void HiRes4Engine::runIntroLoading(Common::SeekableReadStream &adventure) { _display->home(); - _display->setMode(DISPLAY_MODE_TEXT); + _display->setMode(Display::kModeText); const uint kStrings = 4; const uint kStringLen = 39; @@ -459,7 +464,7 @@ void HiRes4Engine::runIntro() { } void HiRes4Engine::init() { - _graphics = new GraphicsMan_v2(*_display); + _graphics = new GraphicsMan_v2(*static_cast(_display)); _boot = new DiskImage(); if (!_boot->open(getDiskImageName(0))) @@ -573,7 +578,7 @@ HiRes4Engine_Atari::~HiRes4Engine_Atari() { } void HiRes4Engine_Atari::init() { - _graphics = new GraphicsMan_v2(*_display); + _graphics = new GraphicsMan_v2(*static_cast(_display)); _boot = new DiskImage(); if (!_boot->open(atariDisks[0])) diff --git a/engines/adl/hires5.cpp b/engines/adl/hires5.cpp index cf09cebeb8..2fdb9fd227 100644 --- a/engines/adl/hires5.cpp +++ b/engines/adl/hires5.cpp @@ -28,7 +28,7 @@ #include "adl/adl_v4.h" #include "adl/detection.h" -#include "adl/display.h" +#include "adl/display_a2.h" #include "adl/graphics.h" #include "adl/disk.h" #include "adl/sound.h" @@ -87,6 +87,7 @@ Common::String HiRes5Engine::getLine() { } void HiRes5Engine::drawLight(uint index, byte color) const { + Display_A2 *display = static_cast(_display); const byte xCoord[5] = { 189, 161, 133, 105, 77 }; const byte yCoord = 72; @@ -94,9 +95,9 @@ void HiRes5Engine::drawLight(uint index, byte color) const { for (int yDelta = 0; yDelta < 4; ++yDelta) for (int xDelta = 0; xDelta < 7; ++xDelta) - _display->putPixel(Common::Point(xCoord[index] + xDelta, yCoord + yDelta), color); + display->putPixel(Common::Point(xCoord[index] + xDelta, yCoord + yDelta), color); - _display->updateHiResScreen(); + display->copyGfxSurface(); } void HiRes5Engine::animateLights() const { @@ -235,25 +236,27 @@ int HiRes5Engine::o_winGame(ScriptEnv &e) { } void HiRes5Engine::runIntro() { + Display_A2 *display = static_cast(_display); + insertDisk(2); StreamPtr stream(_disk->createReadStream(0x10, 0x0, 0x00, 31)); - _display->setMode(DISPLAY_MODE_HIRES); - _display->loadFrameBuffer(*stream); - _display->updateHiResScreen(); + display->setMode(Display::kModeGraphics); + display->loadFrameBuffer(*stream); + display->copyGfxSurface(); inputKey(); - _display->home(); - _display->setMode(DISPLAY_MODE_TEXT); + display->home(); + display->setMode(Display::kModeText); stream.reset(_disk->createReadStream(0x03, 0xc, 0x34, 1)); Common::String menu(readString(*stream)); while (!g_engine->shouldQuit()) { - _display->home(); - _display->printString(menu); + display->home(); + display->printString(menu); Common::String cmd(inputString()); @@ -264,7 +267,7 @@ void HiRes5Engine::runIntro() { } void HiRes5Engine::init() { - _graphics = new GraphicsMan_v3(*_display); + _graphics = new GraphicsMan_v3(*static_cast(_display)); insertDisk(2); diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp index 5cbca1caa2..b34a53e2ad 100644 --- a/engines/adl/hires6.cpp +++ b/engines/adl/hires6.cpp @@ -28,7 +28,7 @@ #include "common/memstream.h" #include "adl/adl_v5.h" -#include "adl/display.h" +#include "adl/display_a2.h" #include "adl/graphics.h" #include "adl/disk.h" @@ -192,20 +192,22 @@ static Common::MemoryReadStream *loadSectors(DiskImage *disk, byte track, byte s } void HiRes6Engine::runIntro() { + Display_A2 *display = static_cast(_display); + insertDisk(0); StreamPtr stream(loadSectors(_disk, 11, 1, 96)); - _display->setMode(DISPLAY_MODE_HIRES); - _display->loadFrameBuffer(*stream); - _display->updateHiResScreen(); + display->setMode(Display::kModeGraphics); + display->loadFrameBuffer(*stream); + display->copyGfxSurface(); delay(256 * 8609 / 1000); - _display->loadFrameBuffer(*stream); - _display->updateHiResScreen(); + display->loadFrameBuffer(*stream); + display->copyGfxSurface(); delay(256 * 8609 / 1000); - _display->loadFrameBuffer(*stream); + display->loadFrameBuffer(*stream); // Load copyright string from boot file Files_AppleDOS *files(new Files_AppleDOS()); @@ -218,16 +220,16 @@ void HiRes6Engine::runIntro() { delete files; - _display->updateHiResScreen(); - _display->home(); - _display->setMode(DISPLAY_MODE_MIXED); - _display->moveCursorTo(Common::Point(0, 21)); - _display->printString(copyright); + display->copyGfxSurface(); + display->home(); + display->setMode(Display::kModeMixed); + display->moveCursorTo(Common::Point(0, 21)); + display->printString(copyright); delay(256 * 8609 / 1000); } void HiRes6Engine::init() { - _graphics = new GraphicsMan_v3(*_display); + _graphics = new GraphicsMan_v3(*static_cast(_display)); insertDisk(0); @@ -326,7 +328,7 @@ void HiRes6Engine::showRoom() { if (!_state.isDark) drawItems(); - _display->updateHiResScreen(); + _display->copyGfxSurface(); setVar(2, 0xff); printString(_roomData.description); } diff --git a/engines/adl/module.mk b/engines/adl/module.mk index 30c64b5ade..450720654b 100644 --- a/engines/adl/module.mk +++ b/engines/adl/module.mk @@ -10,7 +10,7 @@ MODULE_OBJS := \ detection.o \ disk.o \ display.o \ - graphics.o \ + display_a2.o \ hires1.o \ hires2.o \ hires4.o \ -- cgit v1.2.3