aboutsummaryrefslogtreecommitdiff
path: root/engines/lab/dispman.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/lab/dispman.cpp')
-rw-r--r--engines/lab/dispman.cpp950
1 files changed, 950 insertions, 0 deletions
diff --git a/engines/lab/dispman.cpp b/engines/lab/dispman.cpp
new file mode 100644
index 0000000000..17623d4f08
--- /dev/null
+++ b/engines/lab/dispman.cpp
@@ -0,0 +1,950 @@
+/* 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.
+ *
+ */
+
+/*
+ * This code is based on Labyrinth of Time code with assistance of
+ *
+ * Copyright (c) 1993 Terra Nova Development
+ * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
+ *
+ */
+
+#include "graphics/palette.h"
+
+#include "lab/lab.h"
+
+#include "lab/anim.h"
+#include "lab/dispman.h"
+#include "lab/eventman.h"
+#include "lab/music.h"
+#include "lab/image.h"
+#include "lab/resource.h"
+#include "lab/utils.h"
+
+namespace Lab {
+
+DisplayMan::DisplayMan(LabEngine *vm) : _vm(vm) {
+ _longWinInFront = false;
+ _lastMessageLong = false;
+ _actionMessageShown = false;
+
+ _screenBytesPerPage = 0;
+ _curBitmap = nullptr;
+ _displayBuffer = nullptr;
+ _currentDisplayBuffer = nullptr;
+ _fadePalette = nullptr;
+
+ _screenWidth = 0;
+ _screenHeight = 0;
+
+ for (int i = 0; i < 256 * 3; i++)
+ _curVgaPal[i] = 0;
+}
+
+DisplayMan::~DisplayMan() {
+ freePict();
+ delete[] _displayBuffer;
+}
+
+void DisplayMan::loadPict(const Common::String filename) {
+ freePict();
+ _curBitmap = _vm->_resource->openDataFile(filename);
+}
+
+void DisplayMan::loadBackPict(const Common::String fileName, uint16 *highPal) {
+ _fadePalette = highPal;
+ _vm->_anim->_noPalChange = true;
+ readPict(fileName);
+
+ for (int i = 0; i < 16; i++) {
+ highPal[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
+ ((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
+ ((_vm->_anim->_diffPalette[i * 3 + 2] >> 2));
+ }
+
+ _vm->_anim->_noPalChange = false;
+}
+
+void DisplayMan::readPict(const Common::String filename, bool playOnce, bool onlyDiffData, byte *memoryBuffer) {
+ _vm->_anim->stopDiff();
+ loadPict(filename);
+ _vm->updateEvents();
+ _vm->_anim->setOutputBuffer(memoryBuffer);
+ _vm->_anim->readDiff(_curBitmap, playOnce, onlyDiffData);
+}
+
+void DisplayMan::freePict() {
+ delete _curBitmap;
+ _curBitmap = nullptr;
+}
+
+Common::String DisplayMan::getWord(const char *mainBuffer) {
+ Common::String result;
+
+ for (int i = 0; mainBuffer[i] && (mainBuffer[i] != ' ') && (mainBuffer[i] != '\n'); i++)
+ result += mainBuffer[i];
+
+ return result;
+}
+
+Common::String DisplayMan::getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth) {
+ uint16 curWidth = 0;
+ Common::String result;
+
+ while ((*mainBuffer)[0]) {
+ Common::String wordBuffer = getWord(*mainBuffer);
+
+ if ((curWidth + textLength(tf, wordBuffer)) <= lineWidth) {
+ result += wordBuffer;
+ (*mainBuffer) += wordBuffer.size();
+
+ // end of line
+ if ((*mainBuffer)[0] == '\n') {
+ (*mainBuffer)++;
+ break;
+ }
+
+ // append any space after the word
+ if ((*mainBuffer)[0]) {
+ result += (*mainBuffer)[0];
+ (*mainBuffer)++;
+ }
+
+ curWidth = textLength(tf, result);
+ } else
+ break;
+ }
+
+ return result;
+}
+
+int DisplayMan::flowText(TextFont *font, int16 spacing, byte penColor, byte backPen,
+ bool fillBack, bool centerh, bool centerv, bool output, Common::Rect textRect, const char *str, Image *targetImage) {
+
+ byte *saveDisplayBuffer = _currentDisplayBuffer;
+
+ if (targetImage) {
+ _currentDisplayBuffer = targetImage->_imageData;
+ assert(_screenBytesPerPage == (uint32)(targetImage->_width * targetImage->_height));
+ }
+
+ if (fillBack)
+ rectFill(textRect, backPen);
+
+ if (!str)
+ return 0;
+
+ const char *orig = str;
+
+ TextFont *msgFont = font;
+ uint16 fontHeight = textHeight(msgFont) + spacing;
+ uint16 numLines = (textRect.height() + 1) / fontHeight;
+ uint16 width = textRect.width() + 1;
+ uint16 y = textRect.top;
+
+ if (centerv && output) {
+ const char *temp = str;
+ uint16 actlines = 0;
+
+ while (temp[0]) {
+ getLine(msgFont, &temp, width);
+ actlines++;
+ }
+
+ if (actlines <= numLines)
+ y += ((textRect.height() + 1) - (actlines * fontHeight)) / 2;
+ }
+
+ while (numLines && str[0]) {
+ Common::String lineBuffer;
+ lineBuffer = getLine(msgFont, &str, width);
+
+ uint16 x = textRect.left;
+
+ if (centerh)
+ x += (width - textLength(msgFont, lineBuffer)) / 2;
+
+ if (output)
+ drawText(msgFont, x, y, penColor, lineBuffer);
+
+ numLines--;
+ y += fontHeight;
+ }
+
+ _currentDisplayBuffer = saveDisplayBuffer;
+
+ return (str - orig);
+}
+
+void DisplayMan::createBox(uint16 y2) {
+ // Message box area
+ rectFillScaled(4, 154, 315, y2 - 2, 7);
+
+ // Box around message area
+ drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleX(317), 0);
+ drawVLine(_vm->_utils->vgaScaleX(317), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
+ drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(y2), _vm->_utils->vgaScaleX(317), 0);
+ drawVLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
+}
+
+int DisplayMan::longDrawMessage(Common::String str, bool isActionMessage) {
+ if (isActionMessage) {
+ _actionMessageShown = true;
+ } else if (_actionMessageShown) {
+ _actionMessageShown = false;
+ return 0;
+ }
+
+ if (str.empty())
+ return 0;
+
+ _vm->_event->attachButtonList(nullptr);
+
+ if (!_longWinInFront) {
+ _longWinInFront = true;
+ // Clear Area
+ rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
+ }
+
+ createBox(198);
+
+ return flowText(_vm->_msgFont, 0, 1, 7, false, true, true, true, _vm->_utils->vgaRectScale(6, 155, 313, 195), str.c_str());
+}
+
+void DisplayMan::drawMessage(Common::String str, bool isActionMessage) {
+ if (isActionMessage) {
+ _actionMessageShown = true;
+ } else if (_actionMessageShown) {
+ _actionMessageShown = false;
+ return;
+ }
+
+ if (str.empty())
+ return;
+
+ if ((textLength(_vm->_msgFont, str) > _vm->_utils->vgaScaleX(306))) {
+ longDrawMessage(str, isActionMessage);
+ _lastMessageLong = true;
+ } else {
+ if (_longWinInFront) {
+ _longWinInFront = false;
+ drawPanel();
+ }
+
+ createBox(168);
+ drawText(_vm->_msgFont, _vm->_utils->vgaScaleX(7), _vm->_utils->vgaScaleY(155) + _vm->_utils->svgaCord(2), 1, str);
+ _lastMessageLong = false;
+ }
+}
+
+void DisplayMan::drawPanel() {
+ // Clear Area
+ rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
+
+ // First Line
+ drawHLine(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 0);
+ // Second Line
+ drawHLine(0, _vm->_utils->vgaScaleY(149) + 1 + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 5);
+ // Button Separators
+ drawHLine(0, _vm->_utils->vgaScaleY(170), _vm->_utils->vgaScaleX(319), 0);
+
+ if (!_vm->_alternate) {
+ // The horizontal lines under the black one
+ drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
+ _vm->_event->drawButtonList(&_vm->_moveButtonList);
+ } else {
+ if (_vm->getPlatform() != Common::kPlatformWindows) {
+ // Vertical Black lines
+ drawVLine(_vm->_utils->vgaScaleX(124), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(194), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ } else {
+ // Vertical Black lines
+ drawVLine(_vm->_utils->vgaScaleX(90), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(160), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ drawVLine(_vm->_utils->vgaScaleX(230), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
+ }
+
+ // The horizontal lines under the black one
+ drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(122), 4);
+ drawHLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(192), 4);
+ drawHLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
+ // The vertical high light lines
+ drawVLine(_vm->_utils->vgaScaleX(1), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+
+ if (_vm->getPlatform() != Common::kPlatformWindows) {
+ drawVLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ } else {
+ drawVLine(_vm->_utils->vgaScaleX(92), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(162), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ drawVLine(_vm->_utils->vgaScaleX(232), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
+ }
+
+ _vm->_event->drawButtonList(&_vm->_invButtonList);
+ }
+}
+
+void DisplayMan::setUpScreens() {
+ EventManager *e = _vm->_event;
+ ButtonList *moveButtonList = &_vm->_moveButtonList;
+ ButtonList *invButtonList = &_vm->_invButtonList;
+ Image **moveImages = _vm->_moveImages;
+ Image **invImages = _vm->_invImages;
+
+ createScreen(_vm->_isHiRes);
+
+ // TODO: The CONTROL file is not present in the Amiga version
+ Common::File *controlFile = _vm->_resource->openDataFile("P:Control");
+ for (int i = 0; i < 20; i++)
+ _vm->_moveImages[i] = new Image(controlFile, _vm);
+ delete controlFile;
+
+ // Creates the buttons for the movement control panel
+ // The key mapping was only set for the Windows version.
+ // It's very convenient to have those shortcut, so I added them
+ // for all versions. (Strangerke)
+ uint16 y = _vm->_utils->vgaScaleY(173) - _vm->_utils->svgaCord(2);
+ moveButtonList->push_back(e->createButton( 1, y, 0, Common::KEYCODE_t, moveImages[0], moveImages[1]));
+ moveButtonList->push_back(e->createButton( 33, y, 1, Common::KEYCODE_m, moveImages[2], moveImages[3]));
+ moveButtonList->push_back(e->createButton( 65, y, 2, Common::KEYCODE_o, moveImages[4], moveImages[5]));
+ moveButtonList->push_back(e->createButton( 97, y, 3, Common::KEYCODE_c, moveImages[6], moveImages[7]));
+ moveButtonList->push_back(e->createButton(129, y, 4, Common::KEYCODE_l, moveImages[8], moveImages[9]));
+ moveButtonList->push_back(e->createButton(161, y, 5, Common::KEYCODE_i, moveImages[12], moveImages[13]));
+ moveButtonList->push_back(e->createButton(193, y, 6, Common::KEYCODE_LEFT, moveImages[14], moveImages[15]));
+ moveButtonList->push_back(e->createButton(225, y, 7, Common::KEYCODE_UP, moveImages[16], moveImages[17]));
+ moveButtonList->push_back(e->createButton(257, y, 8, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19]));
+ moveButtonList->push_back(e->createButton(289, y, 9, Common::KEYCODE_p, moveImages[10], moveImages[11]));
+
+ // TODO: The INV file is not present in the Amiga version
+ Common::File *invFile = _vm->_resource->openDataFile("P:Inv");
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ for (int imgIdx = 0; imgIdx < 10; imgIdx++)
+ _vm->_invImages[imgIdx] = new Image(invFile, _vm);
+ } else {
+ for (int imgIdx = 0; imgIdx < 6; imgIdx++)
+ _vm->_invImages[imgIdx] = new Image(invFile, _vm);
+ }
+ invButtonList->push_back(e->createButton( 24, y, 0, Common::KEYCODE_ESCAPE, invImages[0], invImages[1]));
+ invButtonList->push_back(e->createButton( 56, y, 1, Common::KEYCODE_g, invImages[2], invImages[3]));
+ invButtonList->push_back(e->createButton( 94, y, 2, Common::KEYCODE_u, invImages[4], invImages[5]));
+ invButtonList->push_back(e->createButton(126, y, 3, Common::KEYCODE_l, moveImages[8], moveImages[9]));
+ invButtonList->push_back(e->createButton(164, y, 4, Common::KEYCODE_LEFT, moveImages[14], moveImages[15]));
+ invButtonList->push_back(e->createButton(196, y, 5, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19]));
+
+ // The windows version has 2 extra buttons for breadcrumb trail
+ // CHECKME: the game is really hard to play without those, maybe we could add something to enable that.
+ if (_vm->getPlatform() == Common::kPlatformWindows) {
+ invButtonList->push_back(e->createButton(234, y, 6, Common::KEYCODE_b, invImages[6], invImages[7]));
+ invButtonList->push_back(e->createButton(266, y, 7, Common::KEYCODE_f, invImages[8], invImages[9]));
+ }
+
+ delete invFile;
+}
+
+void DisplayMan::rectFill(Common::Rect fillRect, byte color) {
+ int width = fillRect.width() + 1;
+ int height = fillRect.height() + 1;
+
+ if (fillRect.left + width > _screenWidth)
+ width = _screenWidth - fillRect.left;
+
+ if (fillRect.top + height > _screenHeight)
+ height = _screenHeight - fillRect.top;
+
+ if ((width > 0) && (height > 0)) {
+ byte *d = getCurrentDrawingBuffer() + fillRect.top * _screenWidth + fillRect.left;
+
+ while (height-- > 0) {
+ byte *dd = d;
+ int ww = width;
+
+ while (ww-- > 0) {
+ *dd++ = color;
+ }
+
+ d += _screenWidth;
+ }
+ }
+}
+
+void DisplayMan::rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
+ rectFill(Common::Rect(x1, y1, x2, y2), color);
+}
+
+void DisplayMan::rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
+ rectFill(_vm->_utils->vgaRectScale(x1, y1, x2, y2), color);
+}
+
+void DisplayMan::drawVLine(uint16 x, uint16 y1, uint16 y2, byte color) {
+ rectFill(x, y1, x, y2, color);
+}
+
+void DisplayMan::drawHLine(uint16 x1, uint16 y, uint16 x2, byte color) {
+ rectFill(x1, y, x2, y, color);
+}
+
+void DisplayMan::screenUpdate() {
+ _vm->_system->copyRectToScreen(_displayBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight);
+ _vm->_system->updateScreen();
+
+ _vm->_event->processInput();
+}
+
+void DisplayMan::createScreen(bool hiRes) {
+ if (hiRes) {
+ _screenWidth = 640;
+ _screenHeight = 480;
+ } else {
+ _screenWidth = 320;
+ _screenHeight = 200;
+ }
+ _screenBytesPerPage = _screenWidth * _screenHeight;
+
+ if (_displayBuffer)
+ delete[] _displayBuffer;
+ _displayBuffer = new byte[_screenBytesPerPage];
+ memset(_displayBuffer, 0, _screenBytesPerPage);
+}
+
+void DisplayMan::setAmigaPal(uint16 *pal) {
+ byte vgaPal[16 * 3];
+ uint16 vgaIdx = 0;
+
+ for (int i = 0; i < 16; i++) {
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0xf00) >> 8) << 2);
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x0f0) >> 4) << 2);
+ vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x00f)) << 2);
+ }
+
+ writeColorRegs(vgaPal, 0, 16);
+ _vm->waitTOF();
+}
+
+void DisplayMan::writeColorRegs(byte *buf, uint16 first, uint16 numReg) {
+ assert(first + numReg <= 256);
+ byte tmp[256 * 3];
+
+ for (int i = 0; i < numReg * 3; i++)
+ tmp[i] = (buf[i] << 2) | (buf[i] >> 4); // better results than buf[i] * 4
+
+ _vm->_system->getPaletteManager()->setPalette(tmp, first, numReg);
+ memcpy(&(_curVgaPal[first * 3]), buf, numReg * 3);
+}
+
+void DisplayMan::setPalette(void *newPal, uint16 numColors) {
+ if (memcmp(newPal, _curVgaPal, numColors * 3) != 0)
+ writeColorRegs((byte *)newPal, 0, numColors);
+}
+
+byte *DisplayMan::getCurrentDrawingBuffer() {
+ if (_currentDisplayBuffer)
+ return _currentDisplayBuffer;
+
+ return _displayBuffer;
+}
+
+void DisplayMan::checkerBoardEffect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int w = x2 - x1 + 1;
+ int h = y2 - y1 + 1;
+
+ if (x1 + w > _screenWidth)
+ w = _screenWidth - x1;
+
+ if (y1 + h > _screenHeight)
+ h = _screenHeight - y1;
+
+ if ((w > 0) && (h > 0)) {
+ byte *d = getCurrentDrawingBuffer() + y1 * _screenWidth + x1;
+
+ while (h-- > 0) {
+ byte *dd = d;
+ int ww = w;
+
+ if (y1 & 1) {
+ dd++;
+ ww--;
+ }
+
+ while (ww > 0) {
+ *dd = penColor;
+ dd += 2;
+ ww -= 2;
+ }
+
+ d += _screenWidth;
+ y1++;
+ }
+ }
+}
+
+void DisplayMan::freeFont(TextFont **font) {
+ if (*font) {
+ if ((*font)->_data)
+ delete[] (*font)->_data;
+
+ delete *font;
+ *font = nullptr;
+ }
+}
+
+uint16 DisplayMan::textLength(TextFont *font, const Common::String text) {
+ uint16 length = 0;
+
+ if (font) {
+ int numChars = text.size();
+ for (int i = 0; i < numChars; i++) {
+ length += font->_widths[(byte)text[i]];
+ }
+ }
+
+ return length;
+}
+
+uint16 DisplayMan::textHeight(TextFont *tf) {
+ return (tf) ? tf->_height : 0;
+}
+
+void DisplayMan::drawText(TextFont *tf, uint16 x, uint16 y, uint16 color, const Common::String text) {
+ byte *vgaTop = getCurrentDrawingBuffer();
+ int numChars = text.size();
+
+ for (int i = 0; i < numChars; i++) {
+ uint32 realOffset = (_screenWidth * y) + x;
+ uint16 curPage = realOffset / _screenBytesPerPage;
+ uint32 segmentOffset = realOffset - (curPage * _screenBytesPerPage);
+ int32 leftInSegment = _screenBytesPerPage - segmentOffset;
+ byte *vgaCur = vgaTop + segmentOffset;
+
+ if (tf->_widths[(byte)text[i]]) {
+ byte *cdata = tf->_data + tf->_offsets[(byte)text[i]];
+ uint16 bwidth = *cdata++;
+ byte *vgaTemp = vgaCur;
+ byte *vgaTempLine = vgaCur;
+
+ for (int rows = 0; rows < tf->_height; rows++) {
+ int32 templeft = leftInSegment;
+
+ vgaTemp = vgaTempLine;
+
+ for (int cols = 0; cols < bwidth; cols++) {
+ uint16 data = *cdata++;
+
+ if (data && (templeft >= 8)) {
+ for (int j = 7; j >= 0; j--) {
+ if ((1 << j) & data)
+ *vgaTemp = color;
+ vgaTemp++;
+ }
+
+ templeft -= 8;
+ } else if (data) {
+ uint16 mask = 0x80;
+ templeft = leftInSegment;
+
+ for (int counterb = 0; counterb < 8; counterb++) {
+ if (templeft <= 0) {
+ curPage++;
+ vgaTemp = vgaTop - templeft;
+ // Set up VGATempLine for next line
+ vgaTempLine -= _screenBytesPerPage;
+ // Set up LeftInSegment for next line
+ leftInSegment += _screenBytesPerPage + templeft;
+ templeft += _screenBytesPerPage;
+ }
+
+ if (mask & data)
+ *vgaTemp = color;
+
+ vgaTemp++;
+
+ mask = mask >> 1;
+ templeft--;
+ }
+ } else {
+ templeft -= 8;
+ vgaTemp += 8;
+ }
+ }
+
+ vgaTempLine += _screenWidth;
+ leftInSegment -= _screenWidth;
+
+ if (leftInSegment <= 0) {
+ curPage++;
+ vgaTempLine -= _screenBytesPerPage;
+ leftInSegment += _screenBytesPerPage;
+ }
+ }
+ }
+
+ x += tf->_widths[(byte)text[i]];
+ }
+}
+
+void DisplayMan::doScrollBlack() {
+ uint16 width = _vm->_utils->vgaScaleX(320);
+ uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+
+ _vm->_event->mouseHide();
+
+ byte *mem = new byte[width * height];
+ int16 by = _vm->_utils->vgaScaleX(4);
+ int16 verticalScroll = height;
+
+ while (verticalScroll > 0) {
+ scrollDisplayY(-by, 0, 0, width - 1, height - 1, mem);
+ verticalScroll -= by;
+
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+
+ delete[] mem;
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::copyPage(uint16 width, uint16 height, uint16 nheight, uint16 startLine, byte *mem) {
+ byte *baseAddr = getCurrentDrawingBuffer();
+
+ uint32 size = (int32)(height - nheight) * (int32)width;
+ mem += startLine * width;
+ uint16 curPage = ((int32)nheight * (int32)width) / _screenBytesPerPage;
+ uint32 offSet = ((int32)nheight * (int32)width) - (curPage * _screenBytesPerPage);
+
+ while (size) {
+ uint32 copySize;
+ if (size > (_screenBytesPerPage - offSet))
+ copySize = _screenBytesPerPage - offSet;
+ else
+ copySize = size;
+
+ size -= copySize;
+
+ memcpy(baseAddr + (offSet >> 2), mem, copySize);
+ mem += copySize;
+ curPage++;
+ offSet = 0;
+ }
+}
+
+void DisplayMan::doScrollWipe(const Common::String filename) {
+ _vm->_event->mouseHide();
+ uint16 width = _vm->_utils->vgaScaleX(320);
+ uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+
+ while (_vm->_music->isSoundEffectActive()) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ }
+
+ readPict(filename, true, true);
+ setPalette(_vm->_anim->_diffPalette, 256);
+ byte *mem = _vm->_anim->_scrollScreenBuffer;
+
+ _vm->updateEvents();
+ uint16 by = _vm->_utils->vgaScaleX(3);
+ uint16 nheight = height;
+ uint16 startLine = 0, onRow = 0;
+
+ while (onRow < _vm->_anim->getDIFFHeight()) {
+ _vm->updateEvents();
+
+ if ((by > nheight) && nheight)
+ by = nheight;
+
+ if ((startLine + by) > (_vm->_anim->getDIFFHeight() - height - 1))
+ break;
+
+ if (nheight)
+ nheight -= by;
+
+ copyPage(width, height, nheight, startLine, mem);
+ screenUpdate();
+
+ if (!nheight)
+ startLine += by;
+
+ onRow += by;
+
+ if (nheight <= (height / 4))
+ by = _vm->_utils->vgaScaleX(5);
+ else if (nheight <= (height / 3))
+ by = _vm->_utils->vgaScaleX(4);
+ else if (nheight <= (height / 2))
+ by = _vm->_utils->vgaScaleX(3);
+ }
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::doScrollBounce() {
+ const uint16 offsets[8] = { 3, 3, 2, 2, 2, 1, 1, 1 };
+ const int multiplier = (_vm->_isHiRes) ? 2 : 1;
+
+ _vm->_event->mouseHide();
+ int width = _vm->_utils->vgaScaleX(320);
+ int height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
+ byte *mem = _vm->_anim->_scrollScreenBuffer;
+
+ _vm->updateEvents();
+ int startLine = _vm->_anim->getDIFFHeight() - height - 1;
+
+ for (int i = 0; i < 5; i++) {
+ _vm->updateEvents();
+ startLine -= (5 - i) * multiplier;
+ copyPage(width, height, 0, startLine, mem);
+ _vm->waitTOF();
+ }
+
+ for (int i = 8; i > 0; i--) {
+ _vm->updateEvents();
+ startLine += offsets[i - 1] * multiplier;
+ copyPage(width, height, 0, startLine, mem);
+ _vm->waitTOF();
+ }
+
+ _vm->_event->mouseShow();
+}
+
+void DisplayMan::doTransWipe(const Common::String filename) {
+ uint16 lastY, linesLast;
+
+ if (_vm->_isHiRes) {
+ linesLast = 3;
+ lastY = 358;
+ } else {
+ linesLast = 1;
+ lastY = 148;
+ }
+
+ uint16 linesDone = 0;
+
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ uint16 curY = i * 2;
+
+ while (curY < lastY) {
+ if (linesDone >= linesLast) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ linesDone = 0;
+ }
+
+ if (j == 0)
+ checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
+ else
+ rectFill(0, curY, _screenWidth - 1, curY + 1, 0);
+ curY += 4;
+ linesDone++;
+ } // while
+ } // for i
+ } // for j
+
+ if (filename.empty())
+ _vm->_curFileName = _vm->getPictName(true);
+ else if (filename[0] > ' ')
+ _vm->_curFileName = filename;
+ else
+ _vm->_curFileName = _vm->getPictName(true);
+
+ byte *bitMapBuffer = new byte[_screenWidth * (lastY + 5)];
+ readPict(_vm->_curFileName, true, false, bitMapBuffer);
+
+ setPalette(_vm->_anim->_diffPalette, 256);
+
+ Image imgSource(_vm);
+ imgSource._width = _screenWidth;
+ imgSource._height = lastY;
+ imgSource.setData(bitMapBuffer, true);
+
+ Image imgDest(_vm);
+ imgDest._width = _screenWidth;
+ imgDest._height = _screenHeight;
+ imgDest.setData(getCurrentDrawingBuffer(), false);
+
+ for (int j = 0; j < 2; j++) {
+ for (int i = 0; i < 2; i++) {
+ uint16 curY = i * 2;
+
+ while (curY < lastY) {
+ if (linesDone >= linesLast) {
+ _vm->updateEvents();
+ _vm->waitTOF();
+ linesDone = 0;
+ }
+
+ imgDest.setData(getCurrentDrawingBuffer(), false);
+
+ if (j == 0) {
+ imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, 2, false);
+ checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
+ } else {
+ uint16 bitmapHeight = (curY == lastY) ? 1 : 2;
+ imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, bitmapHeight, false);
+ }
+ curY += 4;
+ linesDone++;
+ } // while
+ } // for i
+ } // for j
+
+ // bitMapBuffer will be deleted by the Image destructor
+}
+
+void DisplayMan::doTransition(TransitionType transitionType, const Common::String filename) {
+ switch (transitionType) {
+ case kTransitionWipe:
+ case kTransitionTransporter:
+ doTransWipe(filename);
+ break;
+ case kTransitionScrollWipe: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollWipe(filename);
+ break;
+ case kTransitionScrollBlack: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollBlack();
+ break;
+ case kTransitionScrollBounce: // only used in scene 7 (street, when teleporting to the surreal maze)
+ doScrollBounce();
+ break;
+ case kTransitionReadFirstFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
+ readPict(filename, false);
+ break;
+ case kTransitionReadNextFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
+ _vm->_anim->diffNextFrame();
+ break;
+ case kTransitionNone:
+ default:
+ break;
+ }
+}
+
+void DisplayMan::blackScreen() {
+ byte pal[256 * 3];
+ memset(pal, 0, 248 * 3);
+ writeColorRegs(pal, 8, 248);
+
+ _vm->_system->delayMillis(32);
+}
+
+void DisplayMan::whiteScreen() {
+ byte pal[256 * 3];
+ memset(pal, 255, 248 * 3);
+ writeColorRegs(pal, 8, 248);
+}
+
+void DisplayMan::blackAllScreen() {
+ byte pal[256 * 3];
+ memset(pal, 0, 256 * 3);
+ writeColorRegs(pal, 0, 256);
+
+ _vm->_system->delayMillis(32);
+}
+
+void DisplayMan::scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
+ Image img(_vm);
+ img.setData(buffer, false);
+
+ if (x1 > x2)
+ SWAP<uint16>(x1, x2);
+
+ if (y1 > y2)
+ SWAP<uint16>(y1, y2);
+
+ if (dx > 0) {
+ img._width = x2 - x1 + 1 - dx;
+ img._height = y2 - y1 + 1;
+
+ img.readScreenImage(x1, y1);
+ img.drawImage(x1 + dx, y1);
+
+ rectFill(x1, y1, x1 + dx - 1, y2, 0);
+ } else if (dx < 0) {
+ img._width = x2 - x1 + 1 + dx;
+ img._height = y2 - y1 + 1;
+
+ img.readScreenImage(x1 - dx, y1);
+ img.drawImage(x1, y1);
+
+ rectFill(x2 + dx + 1, y1, x2, y2, 0);
+ }
+}
+
+void DisplayMan::scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
+ Image img(_vm);
+ img.setData(buffer, false);
+
+ if (x1 > x2)
+ SWAP<uint16>(x1, x2);
+
+ if (y1 > y2)
+ SWAP<uint16>(y1, y2);
+
+ if (dy > 0) {
+ img._width = x2 - x1 + 1;
+ img._height = y2 - y1 + 1 - dy;
+
+ img.readScreenImage(x1, y1);
+ img.drawImage(x1, y1 + dy);
+
+ rectFill(x1, y1, x2, y1 + dy - 1, 0);
+ } else if (dy < 0) {
+ img._width = x2 - x1 + 1;
+ img._height = y2 - y1 + 1 + dy;
+
+ img.readScreenImage(x1, y1 - dy);
+ img.drawImage(x1, y1);
+
+ rectFill(x1, y2 + dy + 1, x2, y2, 0);
+ }
+}
+
+uint16 DisplayMan::fadeNumIn(uint16 num, uint16 res, uint16 counter) {
+ return (num - ((((int32)(15 - counter)) * ((int32)(num - res))) / 15));
+}
+
+uint16 DisplayMan::fadeNumOut(uint16 num, uint16 res, uint16 counter) {
+ return (num - ((((int32) counter) * ((int32)(num - res))) / 15));
+}
+
+void DisplayMan::fade(bool fadeIn) {
+ uint16 newPal[16];
+
+ for (int i = 0; i < 16; i++) {
+ for (int palIdx = 0; palIdx < 16; palIdx++) {
+ if (fadeIn)
+ newPal[palIdx] = (0x00F & fadeNumIn(0x00F & _fadePalette[palIdx], 0, i)) +
+ (0x0F0 & fadeNumIn(0x0F0 & _fadePalette[palIdx], 0, i)) +
+ (0xF00 & fadeNumIn(0xF00 & _fadePalette[palIdx], 0, i));
+ else
+ newPal[palIdx] = (0x00F & fadeNumOut(0x00F & _fadePalette[palIdx], 0, i)) +
+ (0x0F0 & fadeNumOut(0x0F0 & _fadePalette[palIdx], 0, i)) +
+ (0xF00 & fadeNumOut(0xF00 & _fadePalette[palIdx], 0, i));
+ }
+
+ setAmigaPal(newPal);
+ _vm->waitTOF();
+ _vm->updateEvents();
+ }
+}
+
+} // End of namespace Lab