scummvm/engines/lab/dispman.cpp

768 lines
22 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/music.h"
#include "lab/image.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;
_curapen = 0;
2015-12-06 14:36:49 +01:00
_curBitmap = nullptr;
_displayBuffer = nullptr;
_currentDisplayBuffer = nullptr;
_tempScrollData = nullptr;
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;
}
DisplayMan::~DisplayMan() {
freePict();
}
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.
2014-10-06 14:50:05 +02:00
void DisplayMan::loadPict(const char *filename) {
Common::File *bitmapFile = _vm->_resource->openDataFile(filename);
freePict();
_curBitmap = new byte[bitmapFile->size()];
bitmapFile->read(_curBitmap, bitmapFile->size());
delete bitmapFile;
}
/**
* Reads in a picture into the dest bitmap.
*/
2015-12-08 11:29:23 +02:00
void DisplayMan::readPict(const char *filename, bool playOnce, bool onlyDiffData) {
_vm->_anim->stopDiff();
2014-10-06 14:50:05 +02:00
loadPict(filename);
2014-10-06 14:50:05 +02:00
_vm->_music->updateMusic();
2014-10-06 14:50:05 +02:00
if (!_vm->_music->_doNotFilestopSoundEffect)
_vm->_music->stopSoundEffect();
2014-10-06 14:50:05 +02:00
_dispBitMap._bytesPerRow = _screenWidth;
_dispBitMap._rows = _screenHeight;
_dispBitMap._flags = BITMAPF_VIDEO;
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
}
/**
* Reads in a picture into buffer memory.
*/
byte *DisplayMan::readPictToMem(const char *filename, uint16 x, uint16 y) {
_vm->_anim->stopDiff();
2014-10-06 14:50:05 +02:00
loadPict(filename);
2014-10-06 14:50:05 +02:00
_vm->_music->updateMusic();
2014-10-06 14:50:05 +02:00
if (!_vm->_music->_doNotFilestopSoundEffect)
_vm->_music->stopSoundEffect();
2014-10-06 14:50:05 +02:00
_dispBitMap._bytesPerRow = x;
_dispBitMap._rows = y;
_dispBitMap._flags = BITMAPF_NONE;
_dispBitMap._planes[0] = _curBitmap;
_dispBitMap._planes[1] = _dispBitMap._planes[0] + 0x10000;
_dispBitMap._planes[2] = _dispBitMap._planes[1] + 0x10000;
_dispBitMap._planes[3] = _dispBitMap._planes[2] + 0x10000;
_dispBitMap._planes[4] = _dispBitMap._planes[3] + 0x10000;
2014-10-06 14:50:05 +02:00
_vm->_anim->readDiff(_curBitmap, true);
return _curBitmap;
}
2014-10-06 14:50:05 +02:00
void DisplayMan::freePict() {
delete _curBitmap;
_curBitmap = NULL;
2014-10-06 14:50:05 +02:00
}
2015-12-08 11:27:34 +01:00
//---------------------------------------------------------------------------
//------------ Does all the text rendering to the message boxes. ------------
//---------------------------------------------------------------------------
2014-10-06 14:50:05 +02:00
/**
* Extracts the first word from a string.
*/
2015-12-01 10:35:31 +01:00
static void getWord(char *wordBuffer, const char *mainBuffer, uint16 *wordWidth) {
2014-10-06 14:50:05 +02:00
uint16 width = 0;
2015-12-08 09:19:00 +01:00
while ((mainBuffer[width] != ' ') && mainBuffer[width] && (mainBuffer[width] != '\n')) {
2015-12-01 10:35:31 +01:00
wordBuffer[width] = mainBuffer[width];
2014-10-06 14:50:05 +02:00
width++;
}
2015-12-01 10:35:31 +01:00
wordBuffer[width] = 0;
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
*wordWidth = width;
2014-10-06 14:50:05 +02:00
}
/**
* Gets a line of text for flowText; makes sure that its length is less than
* or equal to the maximum width.
*/
void DisplayMan::getLine(TextFont *tf, char *lineBuffer, const char **mainBuffer, uint16 lineWidth) {
2015-12-01 10:35:31 +01:00
uint16 curWidth = 0, wordWidth;
char wordBuffer[100];
2014-10-06 14:50:05 +02:00
bool doit = true;
2015-12-01 10:35:31 +01:00
lineWidth += textLength(tf, " ", 1);
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
lineBuffer[0] = 0;
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
while ((*mainBuffer)[0] && doit) {
getWord(wordBuffer, *mainBuffer, &wordWidth);
strcat(wordBuffer, " ");
2014-10-06 14:50:05 +02:00
2015-12-01 10:35:31 +01:00
if ((curWidth + textLength(tf, wordBuffer, wordWidth + 1)) <= lineWidth) {
strcat(lineBuffer, wordBuffer);
(*mainBuffer) += wordWidth;
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
2015-12-01 10:35:31 +01:00
curWidth = textLength(tf, lineBuffer, strlen(lineBuffer));
2014-10-06 14:50:05 +02:00
} else
doit = false;
}
}
/**
* Dumps a chunk of text to an arbitrary box; flows it within that box and
* optionally centers it. Returns the number of characters that were
* processed.
* Note: Every individual word MUST be int16 enough to fit on a line, and
* each line less than 255 characters.
*/
2015-12-08 09:19:00 +01:00
uint32 DisplayMan::flowText(
2015-12-08 11:27:34 +01:00
void *font, // the TextAttr pointer
int16 spacing, // How much vertical spacing between the lines
byte pencolor, // pen number to use for text
byte backpen, // the background color
bool fillback, // Whether to fill the background
bool centerh, // Whether to center the text horizontally
bool centerv, // Whether to center the text vertically
bool output, // Whether to output any text
uint16 x1, uint16 y1, // Cords
2015-12-08 09:19:00 +01:00
uint16 x2, uint16 y2,
2015-12-08 11:27:34 +01:00
const char *str) { // The text itself
2015-12-03 11:01:50 +01:00
TextFont *_msgFont = (TextFont *)font;
2014-10-06 14:50:05 +02:00
char linebuffer[256];
const char *temp;
uint16 numlines, actlines, fontheight, width;
uint16 x, y;
if (fillback) {
setAPen(backpen);
rectFill(x1, y1, x2, y2);
2014-10-06 14:50:05 +02:00
}
if (str == NULL)
return 0L;
setAPen(pencolor);
2014-10-06 14:50:05 +02:00
2015-12-03 11:01:50 +01:00
fontheight = textHeight(_msgFont) + spacing;
2014-10-06 14:50:05 +02:00
numlines = (y2 - y1 + 1) / fontheight;
width = x2 - x1 + 1;
y = y1;
if (centerv && output) {
temp = str;
actlines = 0;
while (temp[0]) {
2015-12-03 11:01:50 +01:00
getLine(_msgFont, linebuffer, &temp, width);
2014-10-06 14:50:05 +02:00
actlines++;
}
if (actlines <= numlines)
y += ((y2 - y1 + 1) - (actlines * fontheight)) / 2;
}
temp = str;
while (numlines && str[0]) {
2015-12-03 11:01:50 +01:00
getLine(_msgFont, linebuffer, &str, width);
2014-10-06 14:50:05 +02:00
x = x1;
if (centerh)
2015-12-03 11:01:50 +01:00
x += (width - textLength(_msgFont, linebuffer, strlen(linebuffer))) / 2;
2014-10-06 14:50:05 +02:00
if (output)
2015-12-03 11:01:50 +01:00
text(_msgFont, x, y, pencolor, linebuffer, strlen(linebuffer));
2014-10-06 14:50:05 +02:00
numlines--;
y += fontheight;
}
return (str - temp);
}
2015-12-08 11:27:34 +01:00
uint32 DisplayMan::flowTextScaled(
void *font, // the TextAttr pointer
int16 spacing, // How much vertical spacing between the lines
byte penColor, // pen number to use for text
byte backPen, // the background color
bool fillBack, // Whether to fill the background
bool centerX, // Whether to center the text horizontally
bool centerY, // Whether to center the text vertically
bool output, // Whether to output any text
uint16 x1, uint16 y1, // Cords
uint16 x2, uint16 y2,
const char *str) {
return flowText(font, spacing, penColor, backPen, fillBack, centerX, centerY, output,
_vm->_utils->vgaScaleX(x1), _vm->_utils->vgaScaleY(y1),
_vm->_utils->vgaScaleX(x2), _vm->_utils->vgaScaleY(y2), str);
}
/**
* Calls flowText, but flows it to memory. Same restrictions as flowText.
*/
2015-12-08 09:19:00 +01:00
uint32 DisplayMan::flowTextToMem(Image *destIm,
2015-12-08 11:27:34 +01:00
void *font, // the TextAttr pointer
int16 spacing, // How much vertical spacing between the lines
byte pencolor, // pen number to use for text
byte backpen, // the background color
bool fillback, // Whether to fill the background
bool centerh, // Whether to center the text horizontally
bool centerv, // Whether to center the text vertically
bool output, // Whether to output any text
uint16 x1, uint16 y1, // Cords
2015-12-08 09:19:00 +01:00
uint16 x2, uint16 y2,
2015-12-08 11:27:34 +01:00
const char *str) { // The text itself
uint32 res, vgabyte = _screenBytesPerPage;
2015-12-06 14:36:49 +01:00
byte *tmp = _currentDisplayBuffer;
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
2015-12-06 14:36:49 +01:00
res = flowText(font, spacing, pencolor, backpen, fillback, centerh, centerv, output, x1, y1, x2, y2, str);
2014-10-06 14:50:05 +02:00
_screenBytesPerPage = vgabyte;
2015-12-06 14:36:49 +01:00
_currentDisplayBuffer = tmp;
2014-10-06 14:50:05 +02:00
return res;
}
2015-12-08 11:27:34 +01:00
//----- The control panel stuff -----
2014-10-06 14:50:05 +02:00
void DisplayMan::createBox(uint16 y2) {
2015-12-08 11:27:34 +01:00
// Message box area
setAPen(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
setAPen(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
}
int32 DisplayMan::longDrawMessage(const char *str) {
2015-12-01 10:35:31 +01:00
char newText[512];
2014-10-06 14:50:05 +02:00
if (str == NULL)
return 0;
2014-10-06 14:50:05 +02:00
_vm->_event->attachGadgetList(NULL);
_vm->_event->mouseHide();
2015-12-01 10:35:31 +01:00
strcpy(newText, str);
2014-10-06 14:50:05 +02:00
2015-12-03 11:01:50 +01:00
if (!_longWinInFront) {
_longWinInFront = true;
2015-12-08 11:27:34 +01:00
// Clear Area
setAPen(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 flowTextScaled(_vm->_msgFont, 0, 1, 7, false, true, true, true, 6, 155, 313, 195, str);
2014-10-06 14:50:05 +02:00
}
/**
* Draws a message to the message box.
*/
void DisplayMan::drawMessage(const char *str) {
2015-12-06 17:24:25 +01:00
if (_doNotDrawMessage) {
_doNotDrawMessage = false;
2014-10-06 14:50:05 +02:00
return;
}
if (str) {
if ((textLength(_vm->_msgFont, str, strlen(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);
text(_vm->_msgFont, _vm->_utils->vgaScaleX(7), _vm->_utils->vgaScaleY(155) + _vm->_utils->svgaCord(2), 1, str, strlen(str));
_vm->_event->mouseShow();
2015-12-01 10:35:31 +01:00
_lastMessageLong = false;
2014-10-06 14:50:05 +02:00
}
}
}
/**
* Draws the control panel display.
*/
void DisplayMan::drawPanel() {
_vm->_event->mouseHide();
2015-12-08 11:27:34 +01:00
// Clear Area
setAPen(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
setAPen(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
setAPen(5);
drawHLine(0, _vm->_utils->vgaScaleY(149) + 1 + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319));
2015-12-08 11:27:34 +01:00
// Gadget Separators
setAPen(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) {
setAPen(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));
drawGadgetList(&_vm->_moveGadgetList);
} 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));
}
setAPen(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));
}
drawGadgetList(&_vm->_invGadgetList);
}
_vm->_event->mouseShow();
}
/**
* Sets up the Labyrinth screens, and opens up the initial windows.
*/
2015-12-08 17:19:08 +02:00
void DisplayMan::setUpScreens() {
createScreen(_vm->_isHiRes);
Common::File *controlFile = _vm->_resource->openDataFile("P:Control");
for (uint16 i = 0; i < 20; i++)
_vm->_moveImages[i] = new Image(controlFile);
delete controlFile;
2015-12-08 11:27:34 +01:00
// Creates the gadgets for the movement control panel
uint16 y = _vm->_utils->vgaScaleY(173) - _vm->_utils->svgaCord(2);
// 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)
_vm->_moveGadgetList.push_back(createButton( 1, y, 0, 't', _vm->_moveImages[0], _vm->_moveImages[1]));
_vm->_moveGadgetList.push_back(createButton( 33, y, 1, 'm', _vm->_moveImages[2], _vm->_moveImages[3]));
_vm->_moveGadgetList.push_back(createButton( 65, y, 2, 'o', _vm->_moveImages[4], _vm->_moveImages[5]));
_vm->_moveGadgetList.push_back(createButton( 97, y, 3, 'c', _vm->_moveImages[6], _vm->_moveImages[7]));
_vm->_moveGadgetList.push_back(createButton(129, y, 4, 'l', _vm->_moveImages[8], _vm->_moveImages[9]));
_vm->_moveGadgetList.push_back(createButton(161, y, 5, 'i', _vm->_moveImages[12], _vm->_moveImages[13]));
_vm->_moveGadgetList.push_back(createButton(193, y, 6, VKEY_LTARROW, _vm->_moveImages[14], _vm->_moveImages[15]));
_vm->_moveGadgetList.push_back(createButton(225, y, 7, VKEY_UPARROW, _vm->_moveImages[16], _vm->_moveImages[17]));
_vm->_moveGadgetList.push_back(createButton(257, y, 8, VKEY_RTARROW, _vm->_moveImages[18], _vm->_moveImages[19]));
_vm->_moveGadgetList.push_back(createButton(289, y, 9, 'p', _vm->_moveImages[10], _vm->_moveImages[11]));
Common::File *invFile = _vm->_resource->openDataFile("P:Inv");
if (_vm->getPlatform() == Common::kPlatformWindows) {
for (uint16 imgIdx = 0; imgIdx < 10; imgIdx++)
_vm->_invImages[imgIdx] = new Image(invFile);
} else {
for (uint16 imgIdx = 0; imgIdx < 6; imgIdx++)
_vm->_invImages[imgIdx] = new Image(invFile);
}
_vm->_invGadgetList.push_back(createButton( 24, y, 0, 'm', _vm->_invImages[0], _vm->_invImages[1]));
_vm->_invGadgetList.push_back(createButton( 56, y, 1, 'g', _vm->_invImages[2], _vm->_invImages[3]));
_vm->_invGadgetList.push_back(createButton( 94, y, 2, 'u', _vm->_invImages[4], _vm->_invImages[5]));
_vm->_invGadgetList.push_back(createButton(126, y, 3, 'l', _vm->_moveImages[8], _vm->_moveImages[9]));
_vm->_invGadgetList.push_back(createButton(164, y, 4, VKEY_LTARROW, _vm->_moveImages[14], _vm->_moveImages[15]));
_vm->_invGadgetList.push_back(createButton(196, y, 5, VKEY_RTARROW, _vm->_moveImages[18], _vm->_moveImages[19]));
// The windows version has 2 extra gadgets for breadcrumb trail
// TODO: the game is really hard to play without those, maybe we could add something to enable that.
if (_vm->getPlatform() == Common::kPlatformWindows) {
_vm->_invGadgetList.push_back(createButton(234, y, 6, 'b', _vm->_invImages[6], _vm->_invImages[7]));
_vm->_invGadgetList.push_back(createButton(266, y, 7, 'f', _vm->_invImages[8], _vm->_invImages[9]));
}
delete invFile;
}
/**
* Sets the pen number to use on all the drawing operations.
*/
void DisplayMan::setAPen(byte pennum) {
_curapen = pennum;
}
/**
* Fills in a rectangle.
*/
void DisplayMan::rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
int w = x2 - x1 + 1;
int h = y2 - y1 + 1;
2015-12-06 14:36:49 +01:00
if (x1 + w > _screenWidth)
w = _screenWidth - x1;
2015-12-06 14:36:49 +01:00
if (y1 + h > _screenHeight)
h = _screenHeight - y1;
if ((w > 0) && (h > 0)) {
2015-12-06 14:36:49 +01:00
char *d = (char *)getCurrentDrawingBuffer() + y1 * _screenWidth + x1;
while (h-- > 0) {
char *dd = d;
int ww = w;
while (ww-- > 0) {
*dd++ = _curapen;
}
2015-12-06 14:36:49 +01:00
d += _screenWidth;
}
}
}
void DisplayMan::rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
rectFill(_vm->_utils->vgaScaleX(x1), _vm->_utils->vgaScaleY(y1), _vm->_utils->vgaScaleX(x2), _vm->_utils->vgaScaleY(y2));
}
/**
* Draws a horizontal line.
*/
void DisplayMan::drawVLine(uint16 x, uint16 y1, uint16 y2) {
rectFill(x, y1, x, y2);
}
/**
* Draws a vertical line.
*/
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();
}
/**
* Sets up either a low-res or a high-res 256 color screen.
*/
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;
_displayBuffer = new byte[_screenBytesPerPage]; // FIXME: Memory leak!
}
/**
* Converts an Amiga palette (up to 16 colors) to a VGA palette, then sets
* the VGA palette.
*/
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();
}
/**
* Writes any number of the 256 color registers.
* first: the number of the first color register to write.
* numreg: the number of registers to write
* buf: a char pointer which contains the selected color registers.
* Each value representing a color register occupies 3 bytes in
* the array. The order is red, green then blue. The first byte
* in the array is the red component of the first element selected.
* The length of the buffer is 3 times the number of registers
* selected.
*/
2015-12-06 14:36:49 +01:00
void DisplayMan::writeColorRegs(byte *buf, uint16 first, uint16 numreg) {
byte tmp[256 * 3];
for (int i = 0; i < 256 * 3; i++) {
tmp[i] = buf[i] * 4;
}
g_system->getPaletteManager()->setPalette(tmp, first, numreg);
memcpy(&(_curvgapal[first * 3]), buf, numreg * 3);
}
void DisplayMan::setPalette(void *cmap, uint16 numcolors) {
if (memcmp(cmap, _curvgapal, numcolors * 3) != 0)
writeColorRegs((byte *)cmap, 0, numcolors);
}
/**
* Returns the base address of the current VGA display.
*/
2015-12-06 14:36:49 +01:00
byte *DisplayMan::getCurrentDrawingBuffer() {
if (_currentDisplayBuffer)
return _currentDisplayBuffer;
return _displayBuffer;
}
/**
* Overlays a region on the screen using the desired pen color.
*/
2015-12-06 14:36:49 +01:00
void DisplayMan::overlayRect(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)) {
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;
dd += 2;
ww -= 2;
}
d += _screenWidth;
y1++;
}
}
}
/**
* Closes a font and frees all memory associated with it.
*/
void DisplayMan::closeFont(TextFont *tf) {
if (tf) {
if (tf->_data && tf->_dataLength)
delete[] tf->_data;
delete tf;
}
}
/**
* Returns the length of a text in the specified font.
*/
uint16 DisplayMan::textLength(TextFont *tf, const char *text, uint16 numchars) {
uint16 length = 0;
if (tf) {
for (uint16 i = 0; i < numchars; i++) {
length += tf->_widths[(uint)*text];
text++;
}
}
return length;
}
/**
* Returns the height of a specified font.
*/
uint16 DisplayMan::textHeight(TextFont *tf) {
return (tf) ? tf->_height : 0;
}
/**
* Draws the text to the screen.
*/
void DisplayMan::text(TextFont *tf, uint16 x, uint16 y, uint16 color, const char *text, uint16 numchars) {
byte *VGATop, *VGACur, *VGATemp, *VGATempLine, *cdata;
uint32 RealOffset, SegmentOffset;
int32 templeft, LeftInSegment;
uint16 bwidth, mask, curpage, data;
VGATop = getCurrentDrawingBuffer();
for (uint16 i = 0; i < numchars; i++) {
RealOffset = (_screenWidth * y) + x;
curpage = RealOffset / _screenBytesPerPage;
SegmentOffset = RealOffset - (curpage * _screenBytesPerPage);
LeftInSegment = _screenBytesPerPage - SegmentOffset;
VGACur = VGATop + SegmentOffset;
if (tf->_widths[(uint)*text]) {
cdata = tf->_data + tf->_offsets[(uint)*text];
bwidth = *cdata++;
VGATemp = VGACur;
VGATempLine = VGACur;
for (uint16 rows = 0; rows < tf->_height; rows++) {
VGATemp = VGATempLine;
templeft = LeftInSegment;
for (uint16 cols = 0; cols < bwidth; cols++) {
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) {
mask = 0x80;
templeft = LeftInSegment;
for (uint16 counterb = 0; counterb < 8; counterb++) {
if (templeft <= 0) {
curpage++;
VGATemp = (byte *)(VGATop - templeft);
2015-12-08 11:27:34 +01:00
// Set up VGATempLine for next line
VGATempLine -= _screenBytesPerPage;
2015-12-08 11:27:34 +01:00
// 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[(int)*text];
text++;
}
}
2014-10-06 14:50:05 +02:00
} // End of namespace Lab