scummvm/engines/lab/dispman.cpp

1055 lines
28 KiB
C++
Raw Normal View History

2014-10-06 14:50:05 +02:00
/* 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.
*
*/
2015-12-08 20:31:21 +01:00
#include "graphics/palette.h"
2014-12-27 14:18:40 +01:00
#include "lab/lab.h"
#include "lab/anim.h"
#include "lab/dispman.h"
#include "lab/eventman.h"
#include "lab/music.h"
#include "lab/image.h"
2015-12-08 21:10:54 +01:00
#include "lab/resource.h"
#include "lab/utils.h"
2014-10-06 14:50:05 +02:00
namespace Lab {
DisplayMan::DisplayMan(LabEngine *vm) : _vm(vm) {
_longWinInFront = false;
_lastMessageLong = false;
2015-12-06 17:24:25 +01:00
_doNotDrawMessage = false;
_screenBytesPerPage = 65536;
_curPen = 0;
2015-12-06 14:36:49 +01:00
_curBitmap = nullptr;
_displayBuffer = nullptr;
_currentDisplayBuffer = nullptr;
2015-12-14 08:59:16 +01:00
_fadePalette = nullptr;
2015-12-06 14:36:49 +01:00
_screenWidth = 0;
_screenHeight = 0;
for (int i = 0; i < 256 * 3; i++)
_curvgapal[i] = 0;
_dispBitMap = new BitMap;
}
DisplayMan::~DisplayMan() {
freePict();
delete _dispBitMap;
delete[] _displayBuffer;
}
2015-12-02 11:58:53 +01:00
2015-12-08 11:27:34 +01:00
// From readPict.c. Reads in pictures and animations from disk.
void DisplayMan::loadPict(const Common::String filename) {
freePict();
_curBitmap = _vm->_resource->openDataFile(filename);
}
void DisplayMan::loadBackPict(const Common::String fileName, uint16 *highPal) {
2015-12-14 08:59:16 +01:00
_fadePalette = highPal;
_vm->_anim->_noPalChange = true;
readPict(fileName.c_str(), true);
for (uint16 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(Common::String filename, bool playOnce, bool onlyDiffData, byte *memoryBuffer, uint16 maxHeight) {
_vm->_anim->stopDiff();
2014-10-06 14:50:05 +02:00
loadPict(filename.c_str());
2014-10-06 14:50:05 +02:00
_vm->_music->updateMusic();
2014-10-06 14:50:05 +02:00
if (!_vm->_music->_loopSoundEffect)
_vm->_music->stopSoundEffect();
2014-10-06 14:50:05 +02:00
_dispBitMap->_bytesPerRow = _screenWidth;
_dispBitMap->_drawOnScreen = (memoryBuffer == nullptr);
if (memoryBuffer)
_dispBitMap->_planes[0] = memoryBuffer;
2014-10-06 14:50:05 +02:00
2015-12-08 11:29:23 +02:00
_vm->_anim->readDiff(_curBitmap, playOnce, onlyDiffData);
2014-10-06 14:50:05 +02:00
}
void DisplayMan::freePict() {
delete[] _curBitmap;
_curBitmap = nullptr;
2014-10-06 14:50:05 +02:00
}
Common::String DisplayMan::getWord(const char *mainBuffer) {
Common::String result;
2014-10-06 14:50:05 +02:00
for (int i = 0; mainBuffer[i] && (mainBuffer[i] != ' ') && (mainBuffer[i] != '\n'); i++)
result += mainBuffer[i];
2014-10-06 14:50:05 +02:00
return result;
2014-10-06 14:50:05 +02:00
}
Common::String DisplayMan::getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth) {
uint16 curWidth = 0;
Common::String result;
2014-10-06 14:50:05 +02:00
bool doit = true;
lineWidth += textLength(tf, " ");
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
while ((*mainBuffer)[0] && doit) {
Common::String wordBuffer = getWord(*mainBuffer) + " ";
2014-10-06 14:50:05 +02:00
if ((curWidth + textLength(tf, wordBuffer)) <= lineWidth) {
result += wordBuffer;
(*mainBuffer) += wordBuffer.size() - 1;
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
if ((*mainBuffer)[0] == '\n')
2014-10-06 14:50:05 +02:00
doit = false;
2015-12-01 10:35:31 +01:00
if ((*mainBuffer)[0])
(*mainBuffer)++;
2014-10-06 14:50:05 +02:00
curWidth = textLength(tf, result);
2014-10-06 14:50:05 +02:00
} else
doit = false;
}
return result;
2014-10-06 14:50:05 +02:00
}
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) {
2015-12-14 22:50:09 +01:00
if (fillBack) {
setPen(backPen);
rectFill(textRect);
2014-10-06 14:50:05 +02:00
}
if (!str)
return 0;
2014-10-06 14:50:05 +02:00
2015-12-14 22:50:09 +01:00
setPen(penColor);
2014-10-06 14:50:05 +02:00
TextFont *msgFont = font;
2015-12-14 22:50:09 +01:00
uint16 fontHeight = textHeight(msgFont) + spacing;
uint16 numLines = (textRect.height() + 1) / fontHeight;
uint16 width = textRect.width() + 1;
uint16 y = textRect.top;
Common::String lineBuffer;
2014-10-06 14:50:05 +02:00
if (centerv && output) {
const char *temp = str;
2015-12-14 09:18:01 +01:00
uint16 actlines = 0;
2014-10-06 14:50:05 +02:00
while (temp[0]) {
lineBuffer = getLine(msgFont, &temp, width);
2014-10-06 14:50:05 +02:00
actlines++;
}
2015-12-14 22:50:09 +01:00
if (actlines <= numLines)
y += ((textRect.height() + 1) - (actlines * fontHeight)) / 2;
2014-10-06 14:50:05 +02:00
}
int len = 0;
2015-12-14 22:50:09 +01:00
while (numLines && str[0]) {
lineBuffer = getLine(msgFont, &str, width);
2014-10-06 14:50:05 +02:00
uint16 x = textRect.left;
len += lineBuffer.size();
2014-10-06 14:50:05 +02:00
if (centerh)
x += (width - textLength(msgFont, lineBuffer)) / 2;
2014-10-06 14:50:05 +02:00
if (output)
drawText(msgFont, x, y, penColor, lineBuffer);
2014-10-06 14:50:05 +02:00
2015-12-14 22:50:09 +01:00
numLines--;
y += fontHeight;
2014-10-06 14:50:05 +02:00
}
len--;
return len;
2014-10-06 14:50:05 +02:00
}
int DisplayMan::flowTextToMem(Image *destIm, TextFont *font, int16 spacing, byte penColor,
byte backPen, bool fillBack, bool centerh, bool centerv, bool output, Common::Rect textRect,
const char *str) {
2015-12-14 22:50:09 +01:00
byte *saveDisplayBuffer = _currentDisplayBuffer;
uint32 bytesPerPage = _screenBytesPerPage;
2014-10-06 14:50:05 +02:00
2015-12-06 14:36:49 +01:00
_currentDisplayBuffer = destIm->_imageData;
_screenBytesPerPage = (uint32)destIm->_width * (int32)destIm->_height;
2014-10-06 14:50:05 +02:00
int res = flowText(font, spacing, penColor, backPen, fillBack, centerh, centerv, output, textRect, str);
2014-10-06 14:50:05 +02:00
2015-12-14 22:50:09 +01:00
_screenBytesPerPage = bytesPerPage;
_currentDisplayBuffer = saveDisplayBuffer;
2014-10-06 14:50:05 +02:00
return res;
}
void DisplayMan::createBox(uint16 y2) {
2015-12-08 11:27:34 +01:00
// Message box area
2015-12-14 22:50:09 +01:00
setPen(7);
rectFillScaled(4, 154, 315, y2 - 2);
2015-11-24 23:59:30 +01:00
2015-12-08 11:27:34 +01:00
// Box around message area
2015-12-14 22:50:09 +01:00
setPen(0);
drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleX(317));
drawVLine(_vm->_utils->vgaScaleX(317), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2));
drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(y2), _vm->_utils->vgaScaleX(317));
drawVLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2));
2014-10-06 14:50:05 +02:00
}
int DisplayMan::longDrawMessage(Common::String str) {
if (!str.size())
return 0;
2014-10-06 14:50:05 +02:00
_vm->_event->attachButtonList(nullptr);
_vm->_event->mouseHide();
2015-12-14 09:18:01 +01:00
2015-12-03 11:01:50 +01:00
if (!_longWinInFront) {
_longWinInFront = true;
2015-12-08 11:27:34 +01:00
// Clear Area
2015-12-14 22:50:09 +01:00
setPen(3);
rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199));
2014-10-06 14:50:05 +02:00
}
createBox(198);
_vm->_event->mouseShow();
return flowText(_vm->_msgFont, 0, 1, 7, false, true, true, true, _vm->_utils->vgaRectScale(6, 155, 313, 195), str.c_str());
2014-10-06 14:50:05 +02:00
}
void DisplayMan::drawMessage(Common::String str) {
2015-12-06 17:24:25 +01:00
if (_doNotDrawMessage) {
_doNotDrawMessage = false;
2014-10-06 14:50:05 +02:00
return;
}
if (str.size()) {
if ((textLength(_vm->_msgFont, str) > _vm->_utils->vgaScaleX(306))) {
2014-10-06 14:50:05 +02:00
longDrawMessage(str);
2015-12-01 10:35:31 +01:00
_lastMessageLong = true;
2014-10-06 14:50:05 +02:00
} else {
2015-12-03 11:01:50 +01:00
if (_longWinInFront) {
_longWinInFront = false;
2015-12-01 11:18:11 +01:00
drawPanel();
2014-10-06 14:50:05 +02:00
}
_vm->_event->mouseHide();
2014-10-06 14:50:05 +02:00
createBox(168);
drawText(_vm->_msgFont, _vm->_utils->vgaScaleX(7), _vm->_utils->vgaScaleY(155) + _vm->_utils->svgaCord(2), 1, str);
_vm->_event->mouseShow();
2015-12-01 10:35:31 +01:00
_lastMessageLong = false;
2014-10-06 14:50:05 +02:00
}
}
}
void DisplayMan::drawPanel() {
_vm->_event->mouseHide();
2015-12-08 11:27:34 +01:00
// Clear Area
2015-12-14 22:50:09 +01:00
setPen(3);
rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199));
2015-12-08 11:27:34 +01:00
// First Line
2015-12-14 22:50:09 +01:00
setPen(0);
drawHLine(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319));
2015-12-08 11:27:34 +01:00
// Second Line
2015-12-14 22:50:09 +01:00
setPen(5);
drawHLine(0, _vm->_utils->vgaScaleY(149) + 1 + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319));
2015-12-13 19:36:56 +02:00
// Button Separators
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-08 11:27:34 +01:00
// First black line to separate buttons
drawHLine(0, _vm->_utils->vgaScaleY(170), _vm->_utils->vgaScaleX(319));
if (!_vm->_alternate) {
2015-12-14 22:50:09 +01:00
setPen(4);
2015-12-08 11:27:34 +01:00
// The horizontal lines under the black one
drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319));
2015-12-13 19:36:56 +02:00
_vm->_event->drawButtonList(&_vm->_moveButtonList);
} else {
if (_vm->getPlatform() != Common::kPlatformWindows) {
2015-12-08 11:27:34 +01:00
// Vertical Black lines
drawVLine(_vm->_utils->vgaScaleX(124), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199));
drawVLine(_vm->_utils->vgaScaleX(194), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199));
} else {
2015-12-08 11:27:34 +01:00
// Vertical Black lines
drawVLine(_vm->_utils->vgaScaleX(90), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199));
drawVLine(_vm->_utils->vgaScaleX(160), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199));
drawVLine(_vm->_utils->vgaScaleX(230), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199));
}
2015-12-14 22:50:09 +01:00
setPen(4);
2015-12-08 11:27:34 +01:00
// The horizontal lines under the black one
drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(122));
drawHLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(192));
drawHLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319));
2015-12-08 11:27:34 +01:00
// The vertical high light lines
drawVLine(_vm->_utils->vgaScaleX(1), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
if (_vm->getPlatform() != Common::kPlatformWindows) {
drawVLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
drawVLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
} else {
drawVLine(_vm->_utils->vgaScaleX(92), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
drawVLine(_vm->_utils->vgaScaleX(162), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
drawVLine(_vm->_utils->vgaScaleX(232), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198));
}
2015-12-13 19:36:56 +02:00
_vm->_event->drawButtonList(&_vm->_invButtonList);
}
_vm->_event->mouseShow();
}
2015-12-08 17:19:08 +02:00
void DisplayMan::setUpScreens() {
EventManager *e = _vm->_event;
ButtonList *moveButtonList = &_vm->_moveButtonList;
ButtonList *invButtonList = &_vm->_invButtonList;
Image **moveImages = _vm->_moveImages;
Image **invImages = _vm->_invImages;
2015-12-08 17:19:08 +02:00
createScreen(_vm->_isHiRes);
// TODO: The CONTROL file is not present in the Amiga version
Common::File *controlFile = _vm->_resource->openDataFile("P:Control");
for (uint16 i = 0; i < 20; i++)
2015-12-13 22:51:23 +01:00
_vm->_moveImages[i] = new Image(controlFile, _vm);
delete controlFile;
2015-12-13 19:36:56 +02:00
// 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, 't', moveImages[0], moveImages[1]));
moveButtonList->push_back(e->createButton( 33, y, 1, 'm', moveImages[2], moveImages[3]));
moveButtonList->push_back(e->createButton( 65, y, 2, 'o', moveImages[4], moveImages[5]));
moveButtonList->push_back(e->createButton( 97, y, 3, 'c', moveImages[6], moveImages[7]));
moveButtonList->push_back(e->createButton(129, y, 4, 'l', moveImages[8], moveImages[9]));
moveButtonList->push_back(e->createButton(161, y, 5, 'i', moveImages[12], moveImages[13]));
moveButtonList->push_back(e->createButton(193, y, 6, VKEY_LTARROW, moveImages[14], moveImages[15]));
moveButtonList->push_back(e->createButton(225, y, 7, VKEY_UPARROW, moveImages[16], moveImages[17]));
moveButtonList->push_back(e->createButton(257, y, 8, VKEY_RTARROW, moveImages[18], moveImages[19]));
moveButtonList->push_back(e->createButton(289, y, 9, '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 (uint16 imgIdx = 0; imgIdx < 10; imgIdx++)
2015-12-13 22:51:23 +01:00
_vm->_invImages[imgIdx] = new Image(invFile, _vm);
} else {
for (uint16 imgIdx = 0; imgIdx < 6; imgIdx++)
2015-12-13 22:51:23 +01:00
_vm->_invImages[imgIdx] = new Image(invFile, _vm);
}
invButtonList->push_back(e->createButton( 24, y, 0, 'm', invImages[0], invImages[1]));
invButtonList->push_back(e->createButton( 56, y, 1, 'g', invImages[2], invImages[3]));
invButtonList->push_back(e->createButton( 94, y, 2, 'u', invImages[4], invImages[5]));
invButtonList->push_back(e->createButton(126, y, 3, 'l', moveImages[8], moveImages[9]));
invButtonList->push_back(e->createButton(164, y, 4, VKEY_LTARROW, moveImages[14], moveImages[15]));
invButtonList->push_back(e->createButton(196, y, 5, VKEY_RTARROW, moveImages[18], moveImages[19]));
2015-12-13 19:36:56 +02:00
// The windows version has 2 extra buttons for breadcrumb trail
2015-12-14 22:50:09 +01:00
// 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, 'b', invImages[6], invImages[7]));
invButtonList->push_back(e->createButton(266, y, 7, 'f', invImages[8], invImages[9]));
}
delete invFile;
}
2015-12-14 22:50:09 +01:00
void DisplayMan::setPen(byte penNum) {
_curPen = penNum;
}
void DisplayMan::rectFill(Common::Rect fillRect) {
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)) {
char *d = (char *)getCurrentDrawingBuffer() + fillRect.top * _screenWidth + fillRect.left;
while (height-- > 0) {
char *dd = d;
int ww = width;
while (ww-- > 0) {
*dd++ = _curPen;
}
2015-12-06 14:36:49 +01:00
d += _screenWidth;
}
}
}
void DisplayMan::rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
rectFill(Common::Rect(x1, y1, x2, y2));
}
void DisplayMan::rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
rectFill(_vm->_utils->vgaRectScale(x1, y1, x2, y2));
}
void DisplayMan::drawVLine(uint16 x, uint16 y1, uint16 y2) {
rectFill(x, y1, x, y2);
}
void DisplayMan::drawHLine(uint16 x1, uint16 y, uint16 x2) {
rectFill(x1, y, x2, y);
}
void DisplayMan::screenUpdate() {
2015-12-06 14:36:49 +01:00
g_system->copyRectToScreen(_displayBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight);
g_system->updateScreen();
_vm->_event->processInput();
}
2015-12-08 17:19:08 +02:00
void DisplayMan::createScreen(bool hiRes) {
if (hiRes) {
2015-12-06 14:36:49 +01:00
_screenWidth = 640;
_screenHeight = 480;
} else {
2015-12-06 14:36:49 +01:00
_screenWidth = 320;
_screenHeight = 200;
}
2015-12-06 14:36:49 +01:00
_screenBytesPerPage = _screenWidth * _screenHeight;
2015-12-15 22:16:06 +01:00
if (_displayBuffer)
delete[] _displayBuffer;
_displayBuffer = new byte[_screenBytesPerPage];
}
2015-12-06 14:36:49 +01:00
void DisplayMan::setAmigaPal(uint16 *pal, uint16 numColors) {
byte vgaPal[16 * 3];
uint16 vgaIdx = 0;
if (numColors > 16)
numColors = 16;
for (uint16 i = 0; i < numColors; 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) {
2015-12-06 14:36:49 +01:00
byte tmp[256 * 3];
for (int i = 0; i < 256 * 3; i++)
2015-12-06 14:36:49 +01:00
tmp[i] = buf[i] * 4;
g_system->getPaletteManager()->setPalette(tmp, first, numReg);
memcpy(&(_curvgapal[first * 3]), buf, numReg * 3);
2015-12-06 14:36:49 +01:00
}
2015-12-14 22:50:09 +01:00
void DisplayMan::setPalette(void *newPal, uint16 numColors) {
if (memcmp(newPal, _curvgapal, numColors * 3) != 0)
writeColorRegs((byte *)newPal, 0, numColors);
2015-12-06 14:36:49 +01:00
}
byte *DisplayMan::getCurrentDrawingBuffer() {
if (_currentDisplayBuffer)
return _currentDisplayBuffer;
return _displayBuffer;
}
void DisplayMan::overlayRect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
2015-12-06 14:36:49 +01:00
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)) {
char *d = (char *)getCurrentDrawingBuffer() + y1 * _screenWidth + x1;
while (h-- > 0) {
char *dd = d;
int ww = w;
if (y1 & 1) {
dd++;
ww--;
}
while (ww > 0) {
*dd = penColor;
2015-12-06 14:36:49 +01:00
dd += 2;
ww -= 2;
}
d += _screenWidth;
y1++;
}
}
}
2015-12-19 13:08:54 +01:00
void DisplayMan::closeFont(TextFont **font) {
if (*font) {
if ((*font)->_data)
delete[] (*font)->_data;
2015-12-19 13:08:54 +01:00
delete *font;
*font = nullptr;
}
}
uint16 DisplayMan::textLength(TextFont *font, Common::String text) {
uint16 length = 0;
if (font) {
int numChars = text.size();
for (uint16 i = 0; i < numChars; i++) {
2015-12-20 12:27:31 +01:00
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, Common::String text) {
2015-12-14 09:18:01 +01:00
byte *vgaTop = getCurrentDrawingBuffer();
int numChars = text.size();
2015-12-14 22:50:09 +01:00
for (uint16 i = 0; i < numChars; i++) {
2015-12-14 09:18:01 +01:00
uint32 realOffset = (_screenWidth * y) + x;
2015-12-14 22:50:09 +01:00
uint16 curPage = realOffset / _screenBytesPerPage;
uint32 segmentOffset = realOffset - (curPage * _screenBytesPerPage);
2015-12-14 09:18:01 +01:00
int32 leftInSegment = _screenBytesPerPage - segmentOffset;
byte *vgaCur = vgaTop + segmentOffset;
2015-12-20 12:27:31 +01:00
if (tf->_widths[(byte)text[i]]) {
byte *cdata = tf->_data + tf->_offsets[(byte)text[i]];
2015-12-14 09:18:01 +01:00
uint16 bwidth = *cdata++;
byte *vgaTemp = vgaCur;
byte *vgaTempLine = vgaCur;
for (uint16 rows = 0; rows < tf->_height; rows++) {
2015-12-14 09:18:01 +01:00
int32 templeft = leftInSegment;
vgaTemp = vgaTempLine;
for (uint16 cols = 0; cols < bwidth; cols++) {
2015-12-14 09:18:01 +01:00
uint16 data = *cdata++;
if (data && (templeft >= 8)) {
for (int j = 7; j >= 0; j--) {
if ((1 << j) & data)
2015-12-14 09:18:01 +01:00
*vgaTemp = color;
vgaTemp++;
}
templeft -= 8;
} else if (data) {
2015-12-14 09:18:01 +01:00
uint16 mask = 0x80;
templeft = leftInSegment;
for (uint16 counterb = 0; counterb < 8; counterb++) {
if (templeft <= 0) {
2015-12-14 22:50:09 +01:00
curPage++;
2015-12-14 09:18:01 +01:00
vgaTemp = (byte *)(vgaTop - templeft);
2015-12-08 11:27:34 +01:00
// Set up VGATempLine for next line
2015-12-14 09:18:01 +01:00
vgaTempLine -= _screenBytesPerPage;
2015-12-08 11:27:34 +01:00
// Set up LeftInSegment for next line
2015-12-14 09:18:01 +01:00
leftInSegment += _screenBytesPerPage + templeft;
templeft += _screenBytesPerPage;
}
if (mask & data)
2015-12-14 09:18:01 +01:00
*vgaTemp = color;
2015-12-14 09:18:01 +01:00
vgaTemp++;
mask = mask >> 1;
templeft--;
}
} else {
templeft -= 8;
2015-12-14 09:18:01 +01:00
vgaTemp += 8;
}
}
2015-12-14 09:18:01 +01:00
vgaTempLine += _screenWidth;
leftInSegment -= _screenWidth;
2015-12-14 09:18:01 +01:00
if (leftInSegment <= 0) {
2015-12-14 22:50:09 +01:00
curPage++;
2015-12-14 09:18:01 +01:00
vgaTempLine -= _screenBytesPerPage;
leftInSegment += _screenBytesPerPage;
}
}
}
2015-12-20 12:27:31 +01:00
x += tf->_widths[(byte)text[i]];
}
}
2015-12-12 21:51:31 +01:00
void DisplayMan::doScrollBlack() {
uint16 width = _vm->_utils->vgaScaleX(320);
uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
byte *mem = new byte[width * height];
_vm->_event->mouseHide();
2015-12-13 22:51:23 +01:00
Image img(_vm);
2015-12-12 21:51:31 +01:00
img._width = width;
img._height = height;
img._imageData = mem;
_vm->_music->updateMusic();
img.readScreenImage(0, 0);
_vm->_music->updateMusic();
byte *baseAddr = getCurrentDrawingBuffer();
uint16 by = _vm->_utils->vgaScaleX(4);
uint16 nheight = height;
while (nheight) {
_vm->_music->updateMusic();
if (!_vm->_isHiRes)
_vm->waitTOF();
baseAddr = getCurrentDrawingBuffer();
if (by > nheight)
by = nheight;
mem += by * width;
nheight -= by;
2015-12-14 22:50:09 +01:00
uint32 copySize;
2015-12-12 21:51:31 +01:00
uint32 size = (int32)nheight * (int32)width;
2015-12-14 22:50:09 +01:00
byte *tempMem = mem;
2015-12-12 21:51:31 +01:00
while (size) {
if (size > _screenBytesPerPage)
2015-12-14 22:50:09 +01:00
copySize = _screenBytesPerPage;
2015-12-12 21:51:31 +01:00
else
2015-12-14 22:50:09 +01:00
copySize = size;
2015-12-12 21:51:31 +01:00
2015-12-14 22:50:09 +01:00
size -= copySize;
2015-12-12 21:51:31 +01:00
2015-12-14 22:50:09 +01:00
memcpy(baseAddr, tempMem, copySize);
tempMem += copySize;
2015-12-12 21:51:31 +01:00
}
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
rectFill(0, nheight, width - 1, nheight + by - 1);
screenUpdate();
if (!_vm->_isHiRes) {
if (nheight <= (height / 8))
by = 1;
else if (nheight <= (height / 4))
by = 2;
else if (nheight <= (height / 2))
by = 3;
}
}
delete[] mem;
freePict();
_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(Common::String filename) {
2015-12-12 21:51:31 +01:00
_vm->_event->mouseHide();
uint16 width = _vm->_utils->vgaScaleX(320);
uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
while (_vm->_music->isSoundEffectActive()) {
_vm->_music->updateMusic();
_vm->waitTOF();
}
readPict(filename.c_str(), true, true);
2015-12-12 21:51:31 +01:00
setPalette(_vm->_anim->_diffPalette, 256);
byte *mem = _vm->_anim->_rawDiffBM._planes[0];
_vm->_music->updateMusic();
uint16 by = _vm->_utils->vgaScaleX(3);
uint16 nheight = height;
2015-12-14 09:18:01 +01:00
uint16 startLine = 0, onRow = 0;
2015-12-12 21:51:31 +01:00
while (onRow < _vm->_anim->_headerdata._height) {
_vm->_music->updateMusic();
if ((by > nheight) && nheight)
by = nheight;
if ((startLine + by) > (_vm->_anim->_headerdata._height - 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 *newby, *newby1;
const uint16 newbyd[5] = {5, 4, 3, 2, 1}, newby1d[8] = {3, 3, 2, 2, 2, 1, 1, 1};
const uint16 newbyw[5] = {10, 8, 6, 4, 2}, newby1w[8] = {6, 6, 4, 4, 4, 2, 2, 2};
if (_vm->getPlatform() != Common::kPlatformWindows) {
newby = newbyd;
newby1 = newby1d;
} else {
newby = newbyw;
newby1 = newby1w;
}
_vm->_event->mouseHide();
int width = _vm->_utils->vgaScaleX(320);
int height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
byte *mem = _vm->_anim->_rawDiffBM._planes[0];
_vm->_music->updateMusic();
int startLine = _vm->_anim->_headerdata._height - height - 1;
for (int i = 0; i < 5; i++) {
_vm->_music->updateMusic();
startLine -= newby[i];
copyPage(width, height, 0, startLine, mem);
screenUpdate();
_vm->waitTOF();
}
for (int i = 8; i > 0; i--) {
_vm->_music->updateMusic();
startLine += newby1[i - 1];
copyPage(width, height, 0, startLine, mem);
screenUpdate();
_vm->waitTOF();
}
_vm->_event->mouseShow();
}
void DisplayMan::doTransWipe(CloseDataPtr *closePtrList, Common::String filename) {
2015-12-14 09:18:01 +01:00
uint16 lastY, linesLast;
2015-12-12 21:51:31 +01:00
if (_vm->_isHiRes) {
linesLast = 3;
lastY = 358;
} else {
linesLast = 1;
lastY = 148;
}
2015-12-14 09:18:01 +01:00
uint16 linesDone = 0;
2015-12-12 21:51:31 +01:00
for (uint16 j = 0; j < 2; j++) {
for (uint16 i = 0; i < 2; i++) {
2015-12-14 09:18:01 +01:00
uint16 curY = i * 2;
2015-12-12 21:51:31 +01:00
while (curY < lastY) {
if (linesDone >= linesLast) {
_vm->_music->updateMusic();
_vm->waitTOF();
linesDone = 0;
}
if (j == 9)
overlayRect(0, 0, curY, _screenWidth - 1, curY + 1);
else
rectFill(0, curY, _screenWidth - 1, curY + 1);
curY += 4;
linesDone++;
} // while
} // for i
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
} // for j
if (!filename.size())
2015-12-12 21:51:31 +01:00
_vm->_curFileName = _vm->getPictName(closePtrList);
else if (filename[0] > ' ')
_vm->_curFileName = filename;
else
_vm->_curFileName = _vm->getPictName(closePtrList);
byte *bitMapBuffer = new byte[_screenWidth * (lastY + 5)];
readPict(_vm->_curFileName, true, false, bitMapBuffer, lastY + 5);
setPalette(_vm->_anim->_diffPalette, 256);
2015-12-13 22:51:23 +01:00
Image imSource(_vm);
2015-12-12 21:51:31 +01:00
imSource._width = _screenWidth;
imSource._height = lastY;
imSource._imageData = bitMapBuffer;
2015-12-13 22:51:23 +01:00
Image imDest(_vm);
2015-12-12 21:51:31 +01:00
imDest._width = _screenWidth;
imDest._height = _screenHeight;
imDest._imageData = getCurrentDrawingBuffer();
for (uint16 j = 0; j < 2; j++) {
for (uint16 i = 0; i < 2; i++) {
2015-12-14 09:18:01 +01:00
uint16 curY = i * 2;
2015-12-12 21:51:31 +01:00
while (curY < lastY) {
if (linesDone >= linesLast) {
_vm->_music->updateMusic();
_vm->waitTOF();
linesDone = 0;
}
imDest._imageData = getCurrentDrawingBuffer();
if (j == 0) {
imSource.blitBitmap(0, curY, &imDest, 0, curY, _screenWidth, 2, false);
overlayRect(0, 0, curY, _screenWidth - 1, curY + 1);
} else {
uint16 bitmapHeight = (curY == lastY) ? 1 : 2;
imSource.blitBitmap(0, curY, &imDest, 0, curY, _screenWidth, bitmapHeight, false);
}
curY += 4;
linesDone++;
} // while
} // for i
} // for j
delete[] bitMapBuffer;
}
void DisplayMan::doTransition(TransitionType transitionType, CloseDataPtr *closePtrList, Common::String filename) {
2015-12-12 21:51:31 +01:00
switch (transitionType) {
case kTransitionWipe:
case kTransitionTransporter:
doTransWipe(closePtrList, filename);
break;
case kTransitionScrollWipe:
doScrollWipe(filename);
break;
case kTransitionScrollBlack:
doScrollBlack();
break;
case kTransitionScrollBounce:
doScrollBounce();
break;
case kTransitionReadFirstFrame:
readPict(filename, false);
break;
case kTransitionReadNextFrame:
_vm->_anim->diffNextFrame();
break;
case kTransitionNone:
default:
break;
}
}
void DisplayMan::blackScreen() {
byte pal[256 * 3];
memset(pal, 0, 248 * 3);
writeColorRegs(pal, 8, 248);
g_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);
g_system->delayMillis(32);
}
void DisplayMan::scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
2015-12-13 22:51:23 +01:00
Image im(_vm);
2015-12-12 21:51:31 +01:00
im._imageData = buffer;
if (x1 > x2)
SWAP<uint16>(x1, x2);
if (y1 > y2)
SWAP<uint16>(y1, y2);
if (dx > 0) {
im._width = x2 - x1 + 1 - dx;
im._height = y2 - y1 + 1;
im.readScreenImage(x1, y1);
im.drawImage(x1 + dx, y1);
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
rectFill(x1, y1, x1 + dx - 1, y2);
} else if (dx < 0) {
im._width = x2 - x1 + 1 + dx;
im._height = y2 - y1 + 1;
im.readScreenImage(x1 - dx, y1);
im.drawImage(x1, y1);
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
rectFill(x2 + dx + 1, y1, x2, y2);
}
}
void DisplayMan::scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
2015-12-13 22:51:23 +01:00
Image im(_vm);
2015-12-12 21:51:31 +01:00
im._imageData = buffer;
if (x1 > x2)
SWAP<uint16>(x1, x2);
if (y1 > y2)
SWAP<uint16>(y1, y2);
if (dy > 0) {
im._width = x2 - x1 + 1;
im._height = y2 - y1 + 1 - dy;
im.readScreenImage(x1, y1);
im.drawImage(x1, y1 + dy);
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
rectFill(x1, y1, x2, y1 + dy - 1);
} else if (dy < 0) {
im._width = x2 - x1 + 1;
im._height = y2 - y1 + 1 + dy;
im.readScreenImage(x1, y1 - dy);
im.drawImage(x1, y1);
2015-12-14 22:50:09 +01:00
setPen(0);
2015-12-12 21:51:31 +01:00
rectFill(x1, y2 + dy + 1, x2, y2);
}
}
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 res) {
uint16 newPal[16];
for (uint16 i = 0; i < 16; i++) {
for (uint16 palIdx = 0; palIdx < 16; palIdx++) {
if (fadeIn)
2015-12-14 08:59:16 +01:00
newPal[palIdx] = (0x00F & fadeNumIn(0x00F & _fadePalette[palIdx], 0x00F & res, i)) +
(0x0F0 & fadeNumIn(0x0F0 & _fadePalette[palIdx], 0x0F0 & res, i)) +
(0xF00 & fadeNumIn(0xF00 & _fadePalette[palIdx], 0xF00 & res, i));
2015-12-12 21:51:31 +01:00
else
2015-12-14 08:59:16 +01:00
newPal[palIdx] = (0x00F & fadeNumOut(0x00F & _fadePalette[palIdx], 0x00F & res, i)) +
(0x0F0 & fadeNumOut(0x0F0 & _fadePalette[palIdx], 0x0F0 & res, i)) +
(0xF00 & fadeNumOut(0xF00 & _fadePalette[palIdx], 0xF00 & res, i));
2015-12-12 21:51:31 +01:00
}
setAmigaPal(newPal, 16);
_vm->waitTOF();
_vm->_music->updateMusic();
}
}
2014-10-06 14:50:05 +02:00
} // End of namespace Lab