diff options
Diffstat (limited to 'engines/lab/dispman.cpp')
-rw-r--r-- | engines/lab/dispman.cpp | 961 |
1 files changed, 961 insertions, 0 deletions
diff --git a/engines/lab/dispman.cpp b/engines/lab/dispman.cpp new file mode 100644 index 0000000000..d642f2fed5 --- /dev/null +++ b/engines/lab/dispman.cpp @@ -0,0 +1,961 @@ +/* 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 "common/file.h" +#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/interface.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, MKTAG('D', 'I', 'F', 'F')); +} + +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->_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->_interface->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->_interface->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->_interface->drawButtonList(&_vm->_invButtonList); + } +} + +void DisplayMan::setUpScreens() { + Interface *i = _vm->_interface; + 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 j = 0; j < 20; j++) + _vm->_moveImages[j] = 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(i->createButton( 1, y, 0, Common::KEYCODE_t, moveImages[0], moveImages[1])); + moveButtonList->push_back(i->createButton( 33, y, 1, Common::KEYCODE_m, moveImages[2], moveImages[3])); + moveButtonList->push_back(i->createButton( 65, y, 2, Common::KEYCODE_o, moveImages[4], moveImages[5])); + moveButtonList->push_back(i->createButton( 97, y, 3, Common::KEYCODE_c, moveImages[6], moveImages[7])); + moveButtonList->push_back(i->createButton(129, y, 4, Common::KEYCODE_l, moveImages[8], moveImages[9])); + moveButtonList->push_back(i->createButton(161, y, 5, Common::KEYCODE_i, moveImages[12], moveImages[13])); + moveButtonList->push_back(i->createButton(193, y, 6, Common::KEYCODE_LEFT, moveImages[14], moveImages[15])); + moveButtonList->push_back(i->createButton(225, y, 7, Common::KEYCODE_UP, moveImages[16], moveImages[17])); + moveButtonList->push_back(i->createButton(257, y, 8, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19])); + moveButtonList->push_back(i->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); + } + + if (_vm->getPlatform() == Common::kPlatformWindows) { + invButtonList->push_back(i->createButton( 24, y, 0, Common::KEYCODE_ESCAPE, invImages[0], invImages[1])); + invButtonList->push_back(i->createButton( 56, y, 1, Common::KEYCODE_g, invImages[2], invImages[3])); + invButtonList->push_back(i->createButton( 94, y, 2, Common::KEYCODE_u, invImages[4], invImages[5])); + invButtonList->push_back(i->createButton(126, y, 3, Common::KEYCODE_l, moveImages[8], moveImages[9])); + invButtonList->push_back(i->createButton(164, y, 4, Common::KEYCODE_LEFT, moveImages[14], moveImages[15])); + invButtonList->push_back(i->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. + invButtonList->push_back(i->createButton(234, y, 6, Common::KEYCODE_b, invImages[6], invImages[7])); + invButtonList->push_back(i->createButton(266, y, 7, Common::KEYCODE_f, invImages[8], invImages[9])); + } else { + invButtonList->push_back(i->createButton( 58, y, 0, Common::KEYCODE_ESCAPE, invImages[0], invImages[1])); + invButtonList->push_back(i->createButton( 90, y, 1, Common::KEYCODE_g, invImages[2], invImages[3])); + invButtonList->push_back(i->createButton(128, y, 2, Common::KEYCODE_u, invImages[4], invImages[5])); + invButtonList->push_back(i->createButton(160, y, 3, Common::KEYCODE_l, moveImages[8], moveImages[9])); + invButtonList->push_back(i->createButton(198, y, 4, Common::KEYCODE_LEFT, moveImages[14], moveImages[15])); + invButtonList->push_back(i->createButton(230, y, 5, Common::KEYCODE_RIGHT, moveImages[18], moveImages[19])); + } + + 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->_event->processInput(); + + _vm->_system->copyRectToScreen(_displayBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight); + _vm->_console->onFrame(); + _vm->_system->updateScreen(); +} + +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); +} + +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->updateEvents(); + _vm->waitTOF(); + _vm->waitTOF(); + } +} + +} // End of namespace Lab |