aboutsummaryrefslogtreecommitdiff
path: root/engines/adl
diff options
context:
space:
mode:
authorWalter van Niftrik2018-07-28 14:39:12 +0200
committerWalter van Niftrik2019-07-16 16:24:19 +0200
commit0cd761086a72e9fd83c23f1c6267fe79829f3f07 (patch)
treec8d709ab75325f3d84aad623aab628d203f15e9b /engines/adl
parentbfa52c7b9ec19505e16fc27541e2ff82d295b5f3 (diff)
downloadscummvm-rg350-0cd761086a72e9fd83c23f1c6267fe79829f3f07.tar.gz
scummvm-rg350-0cd761086a72e9fd83c23f1c6267fe79829f3f07.tar.bz2
scummvm-rg350-0cd761086a72e9fd83c23f1c6267fe79829f3f07.zip
ADL: Refactor graphics code
Diffstat (limited to 'engines/adl')
-rw-r--r--engines/adl/adl.cpp17
-rw-r--r--engines/adl/adl_v2.cpp11
-rw-r--r--engines/adl/adl_v5.cpp2
-rw-r--r--engines/adl/console.cpp4
-rw-r--r--engines/adl/display.cpp531
-rw-r--r--engines/adl/display.h94
-rw-r--r--engines/adl/display_a2.cpp477
-rw-r--r--engines/adl/display_a2.h85
-rw-r--r--engines/adl/graphics.cpp475
-rw-r--r--engines/adl/graphics.h553
-rw-r--r--engines/adl/hires1.cpp24
-rw-r--r--engines/adl/hires2.cpp6
-rw-r--r--engines/adl/hires4.cpp59
-rw-r--r--engines/adl/hires5.cpp25
-rw-r--r--engines/adl/hires6.cpp30
-rw-r--r--engines/adl/module.mk2
16 files changed, 1275 insertions, 1120 deletions
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<AdlEngine *>(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<AdlEngine *>(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 T>
+class GraphicsMan_v1 : public GraphicsMan {
+public:
+ using GraphicsMan::_bounds;
+
+ GraphicsMan_v1<T>(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 T>
+class GraphicsMan_v2 : public GraphicsMan_v1<T> {
public:
- GraphicsMan_v2(Display &display) : GraphicsMan(display), _color(0) { }
+ using GraphicsMan::_bounds;
+ using GraphicsMan_v1<T>::_display;
+ using GraphicsMan_v1<T>::drawLine;
+ using GraphicsMan_v1<T>::putPixel;
+
+ GraphicsMan_v2<T>(T &display) : GraphicsMan_v1<T>(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 T>
+class GraphicsMan_v3 : public GraphicsMan_v2<T> {
public:
- GraphicsMan_v3(Display &display) : GraphicsMan_v2(display) { }
+ using GraphicsMan::_bounds;
+ using GraphicsMan_v1<T>::_display;
+ using GraphicsMan_v2<T>::canFillAt;
+ using GraphicsMan_v2<T>::fillRow;
+ using GraphicsMan_v2<T>::getPatternColor;
+
+ GraphicsMan_v3<T>(T &display) : GraphicsMan_v2<T>(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 <class T>
+void GraphicsMan_v1<T>::clearScreen() const {
+ _display.setMode(Display::kModeMixed);
+ _display.clear(getClearColor());
+}
+
+// Draws a four-connected line
+template <class T>
+void GraphicsMan_v1<T>::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 <class T>
+void GraphicsMan_v1<T>::putPixel(const Common::Point &p, byte color) const {
+ if (_bounds.contains(p))
+ _display.putPixel(p, color);
+}
+
+template <class T>
+void GraphicsMan_v1<T>::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 <class T>
+void GraphicsMan_v1<T>::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 <class T>
+void GraphicsMan_v1<T>::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 <class T>
+bool GraphicsMan_v2<T>::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 <class T>
+bool GraphicsMan_v2<T>::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 <class T>
+byte GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+bool GraphicsMan_v2<T>::canFillAt(const Common::Point &p, const bool stopBit) {
+ return _display.getPixelBit(p) != stopBit && _display.getPixelBit(Common::Point(p.x + 1, p.y)) != stopBit;
+}
+
+template <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v2<T>::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 <class T>
+void GraphicsMan_v3<T>::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 <class T>
+void GraphicsMan_v3<T>::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_A2 *>(_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_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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_A2 *>(_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_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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_A2 *>(_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<Display_A2>(*static_cast<Display_A2 *>(_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 \