scummvm/engines/lab/dispman.cpp
2020-02-16 13:07:19 +02:00

961 lines
27 KiB
C++

/* 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->_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